• java多线程学习


    参考:

    http://blog.csdn.net/stellaah/article/details/6798244

    http://bbs.csdn.net/topics/300116354

    http://blog.csdn.net/ghsau/article/details/7421217

    http://blog.csdn.net/sd0902/article/details/8395677

    创建线程:

    创建线程过程:
    1.继承Thread

    class 类名A extends Thread
    {
    public void run(){}
    }
    
    2.实例对象
    Thread t=new 类名A();
    
    3.启用线程
    t.start();自动会去运行run().
    

      

    2.Runable接口

    实现Runnable接口创建线程
    
    1.实现Runnable接口
    类名A implements Runnable()
    {
    	public void run(){}
    }
    
    2.启用线程
    new Thread(类名A的对象).start();
    

    区别:

    使用Runnable接口创建多线程,适合多个相同的程序代码的线程去处理分享同一个资源的情况,把虚拟CPU(线程)同程序的代码数据有效分离,较好体现了面向对象的设计思想.

    setDeamon(true)

    设置守护线程,程序非守护线程全部退出时,守护线程自动退出。

    join(),join(msecond) 合并线程(如何实现一个线程执行中让另一个线程先执行然后再继续执行自己)

    t1.join(500) 打断当前线程执行t1线程,500msecond 如果t1线程死亡 则直接继续执行当前线程

    package com.thread;
    public class JoinThread
    {
        public static void main(String[]args)
        {
            Thread o=new OneThread();
    //        o.start();
            
            int index=0;
            while(true)
            {
                System.out.println("main->>"+index+"  "+Thread.currentThread().getName());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                if(index++==3)
                {
                    try
                    {
                        o.start();
                        o.join();//把o对应的线程合并10000毫秒    
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();//输出导致异常更为详细的信息
                    }
                }
            }
        }
    }
    
    
    class OneThread extends Thread
    {
        public void run()
        {
            
            int i = 1; 
            while(++i<10)
            {
                System.out.println("OneThread->>"+Thread.currentThread().getName());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }    
    }
    
    /*
    运行的结果:
    先是两个线程交替执行,main()方法的线程被执行30次后执行run方法的线程.
    run方法被执行10000毫秒后就变为刚开始时的样子---两个线程交替执行.
    */

    Yield()

    在多线程程序中,为了防止某线程独占CPU资源(这样其它的线程就得不到"响应"了).可以让当前执行的线程"休息"一下.但是这种thread.yield() 调用,并不保证下一个运行的线程就一定不是该线程.

    public class Test extends Thread {   
      public static void main(String[] args) {   
        for (int i = 1; i <= 2; i++) {   
          new Test().start();   
        }   
      }   
      
      public void run() {   
        System.out.print("1");   
        yield();   
        System.out.print("2");   
      }   
    }  
        输出结果: 1122 或者 1212

    synchronized

    synchronized代码块的用法-synchronized(Object){}

    synchronized方法的用法需要与run()方法两个结合起来用

    wait() notify

    wait()休眠放弃资源控制锁

    notify 唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。

    notifyAll()  唤醒在此对象监视器上等待的所有线程

    Timer TimerTask

    自JDK5之后,可以用ScheduledThreadPoolExecutor来替代Timer。

    ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);// 效果类似于Timer定时器

    import java.util.*;
    class ZhaDan extends TimerTask  //炸弹
    {
    	public void run()
    	{
    		System.out.println("Boang... ...炸了!");
    	}	
    }
    
    class TimerTest
    {
    	public static void main(String[]args)
    	{
    		Timer t=new Timer();//创建定时器对象
    		ZhaDan z=new ZhaDan();//创建炸弹对象
    		t.schedule(z,1000,2000);//隔1秒引爆炸弹.之后就是每2秒一炸
    
    	while(true)
    	{
    		try{Thread.sleep(1000);}catch(Exception e){}
    		System.out.println(new Date().getSeconds());//输出当前时间的秒
    		
    	}
    
    	}
    	
    }

    中断线程  

    while(flag)

    用thread.interrupt()
    或ThreadPoolExecutor.shutdown()

    package cn.com.interrupt;
    
    import java.util.Scanner;
    
    public class Test extends Thread {
        private String name;
        
        public Test(String name) {
            this.name = name;
        }
        
        public void write() {
            System.out.print(name);
        }
        
        public static void main(String[]args) throws Exception{
            Thread  t1=new Test("myThread");
            t1.start();
            Scanner sc=new Scanner(System.in);
            String s;
    
        
            Thread.sleep(5000);
            t1.interrupt();
        }
        
       
        public void run() {
                    for(int i=0;;i++){
                    if(this.isInterrupted()){
                        System.out.println("exit*****************");
                        return;
                    }
                    write();
                    System.out.println();
    
            }
        }
        
    }

     线程同步问题首先要说明Java线程的两个特性:可见性,有序性

     每个线程都有自己的工作内存(线程栈),工作内存存储了主内存Count对象的一个副本,当线程操作Count对象时,首先从主内存复制Count对象到工作内存中,然后执行代码count.count(),改变了num值,最后用工作内存Count刷新主内存Count。当一个对象在多个内存中都存在副本时,如果一个内存修改了共享变量,其它线程也应该能够看到被修改后的值,此为可见性

    多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程,一个最经典的例子就是银行汇款问题,一个银行账户存款100,这时一个人从该账户取10元,同时另一个人向该账户汇10元,那么余额应该还是100。那么此时可能发生这种情况,A线程负责取款,B线程负责汇款,A从主内存读到100,B从主内存读到100,A执行减10操作,并将数据刷新到主内存,这时主内存数据100-10=90,而B内存执行加10操作,并将数据刷新到主内存,最后主内存数据100+10=110,显然这是一个严重的问题,我们要保证A线程和B线程有序执行,先取款后汇款或者先汇款后取款,此为有序性

    synchronized volitile

    synchronized:

    1.修饰变量

    sychronized(obj){

    2.修饰方法

    void sychronized funA(){

    }

    每个锁对都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个线程被唤醒(notify)后,才会进入到就绪队列,等待CPU的调度,反之,当一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒,这个涉及到线程间的通信,当第一个线程执行输出方法时,获得同步锁,执行输出方法,恰好此时第二个线程也要执行输出方法,但发现同步锁没有被释放,第二个线程就会进入就绪队列,等待锁被释放。一个线程执行互斥代码过程如下:

            1. 获得同步锁;

            2. 清空工作内存;

            3. 从主内存拷贝对象副本到工作内存;

            4. 执行代码(计算或者输出等);

            5. 刷新主内存数据;

            6. 释放同步锁。

            所以,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。

    volitile:

    修饰变量 不能和final一起修饰

    static volatile int i = 0, j = 0;

    volatile可以将共享变量的改变直接响应到主内存中,这样保证了主内存中的值一致性可以保证内存可见性,不能保证并发有序性

    另 volatile 修饰函数 表示编译器不进行代码优化

    线程池

    创建一个可重用固定线程集合的线程池

    ExecutorService threadPool = Executors.newFixedThreadPool(3);

    创建一个可根据需要创建新线程的线程池

    ExecutorService threadPool = Executors.newCachedThreadPool();

    创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程

    ExecutorService threadPool = Executors.newSingleThreadExecutor();

    创建一个可安排在给定延迟后运行命令或者定期地执行的线程池。

    ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);

    Future Callable

    http://openhome.cc/Gossip/DesignPattern/FuturePattern.htm

     Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值

    Future模式在請求發生時,會先產生一個Future物件給發出請求的客戶,而同時間,真正的目標物件之生成,由一個 新的執行緒持續進行(即 Worker Thread),真正的目標物件生成之後,將之設定至Future之中,而當客戶端真正需要目標物件時, 目標物件也已經準備好,可以讓客戶提取使用。

    Lock 锁

    更广泛,继承类更多
    private
    Lock lock = new ReentrantLock()
    private ReadWriteLock rwl = new ReentrantReadWriteLock();
    public interface Lock {
      void lock();
        void lockInterruptibly() throws InterruptedException;
     boolean tryLock();
     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
       void unlock();
       Condition newCondition();
    }
    public class LockTest {
        public static void main(String[] args) {
            final Outputter1 output = new Outputter1();
            new Thread() {
                public void run() {
                    output.output("zhangsan");
                };
            }.start();        
            new Thread() {
                public void run() {
                    output.output("lisi");
                };
            }.start();
        }
    }
    class Outputter1 {
        private Lock lock = new ReentrantLock();// 锁对象
        public void output(String name) {
            // TODO 线程输出方法
            lock.lock();// 得到锁
            try {
                for(int i = 0; i < name.length(); i++) {
                    System.out.print(name.charAt(i));
                }
            } finally {
                lock.unlock();// 释放锁
            }
        }
    }

     死锁实例::

    package com.test;
    
    public class SynchronizedSisuo {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            SynchronizedSisuo ss = new SynchronizedSisuo();
            ss.t1.start();
        }
    
        Thread t1 = new Thread(new Runnable() {
    
            @Override
            public void run() {
                t1Run();
            }
        });
    
        Thread t2 = new Thread(new Runnable() {
    
            @Override
            public void run() {
                t2Run();
            }
        });
    
        Object obj = new Object();
    
        public void t1Run() {
    
            synchronized (obj) {
                System.out.println("1111111>>>pre");
                t2.start();
                try {
                    t2.join();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("1111111>>>pos");
            }
        }
    
        public void t2Run() {
            synchronized (obj) {
                System.out.println("2222222>>>pre");
                System.out.println("2222222>>>pos");
            }
        }
    }
  • 相关阅读:
    【BZOJ-1507】Editor 块状链表
    【BZOJ-4456】旅行者 分治 + 最短路
    【BZOJ-3262】陌上花开 CDQ分治(3维偏序)
    【BZOJ-1176&2683】Mokia&简单题 CDQ分治
    【BZOJ-1962】模型王子 DP 猜数问题
    【BZOJ-3786】星系探索 Splay + DFS序
    【BZOJ-1552&3506】robotic sort&排序机械臂 Splay
    【BZOJ-4688】One-Dimensional 矩阵乘法
    【BZOJ-4692】Beautiful Spacing 二分答案 + 乱搞(DP?)
    Java中接口式的匿名内部类的构造方法
  • 原文地址:https://www.cnblogs.com/wjw334/p/3613888.html
Copyright © 2020-2023  润新知