多线程--Java

多线程:

1.进程和线程

进程是资源分配的最小单位,线程是CPU调度的最小单位。

  •   每个进程的创建都需要系统为其开辟资源内存空间,并发执行的程序在执行过程中分配和管理资源的基本单位,速度和销毁也较慢。进程和进程之间一般没有关联性。 System.Diagnostics.Process 进程的创建类,属于系统资源。
  •   线程是运行在进程中的可认为是小子进程,线程共享调用进程中的资源内存空间,多个线程同时运行就出现并发线程,线程的调度顺序如果不影响结果且较占用时间,则可使用多线程。
  •   服务是管理和协调守护进程的。
  •       任务是完成某项操作的活动。可以是进程,可以是线程,可大可小。

  比如Tomcat的webapp下有两个程序project1和project2.这两个程序默认各自会有一个进程,但一个程序也可开辟多个进程,一般各进程间没有资源的互相调用,且可独立移出时才开辟(浏览器的新建标签页,程序中消息推送功能)。而每次用户的请求服务都会生成一个主线程,如果后台java中创建多个Thread 子线程,就会出现并发情况,这些子线程共享进程的资源空间,速度快,生成销毁也快。

2. 并行和并发

  并行是多条线路同时进行。

  并发是多个请求同时抢占一个资源。

  以打饭为例:并行,就是开了多个窗口,这些人可以排成好几个队进行打饭操作。并发,一个窗口多个人在等待,这些人没有先后顺序,谁先到cpu口,谁先执行。不一定会按照ABC顺序进行。

3.synchronized关键字

  线程的调度顺序影响其结果,则需要同步锁(例如:银行系统中的存取,必须先存后取,不能存取都开线程后,让任意优先)。每一个对象都会有一个默认的隐形锁,单线程不起作用。多线程调用时,就会查找synchronized是否起作用。对象加锁和解锁是很耗性能的,因此慎用,当然安全比性能优先。

Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。

wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。

当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

  锁定代码块,会锁定传入类对这部分代码的访问控制, 以以下代码为例:

1 package jquery.test.interview;
 2 
 3 /**
 4  * 银行存取业务
 5  * 
 6  * @author DennyZhao
 7  * @date 2017年6月29日
 8  * @version 1.0
 9  */
10 public class BankAccess {
11     
12     private int money;
13     
14     /**
15      * 存入钱
16      * @param store
17      */
18     public void saveMoney(int store){
19         money+=store;
20     }
21     
22     /**
23      * 减去手续费
24      */
25     public void getoutMoney(int out){
26         money-=out;
27     }
28     
29     /**
30      * 查看钱
31      */
32     public int searchMoney(){
33         return money;
34     }
35 }
36 
37 
38 -----------------------------银行操作类
39 package jquery.test.interview;
40 
41 public class BankTreader implements Runnable {
42     /** 创建银行操作类 **/
43     private BankAccess bank;
44     
45     private int saveMoney;
46     
47     public int getSaveMoney() {
48         return saveMoney;
49     }
50 
51     public void setSaveMoney(int saveMoney) {
52         this.saveMoney = saveMoney;
53     }
54 
55     /**
56      * 构造类
57      * @param bank
58      */
59     public BankTreader(BankAccess bank){
60         this.bank = bank;
61     }
62     
63     public void handlerBank(){
64         synchronized(bank){
65             bank.saveMoney(saveMoney); //存入
66             bank.getoutMoney((int)Math.round(bank.searchMoney()*0.01));//收取总额手续费,当然实际银行不会这样
67             System.out.println("---------" + bank.searchMoney()); //查看
68         }
69     }
70     @Override
71     public void run() {
72         this.handlerBank();
73     }
74 
75 --------------------------------------------
76 测试方法:
77     public static void main(String[] args) {
78         BankAccess bank = new BankAccess();
79         BankTreader handler = new BankTreader(bank);
80         handler.setSaveMoney(500);
81         Thread t1 = new Thread(handler,"t1");
82         handler.setSaveMoney(300);
83         Thread t2 = new Thread(handler,"t2");
84         t1.start();
85         t2.start();
86     }
87 
88 结果:
89 ---------297
90 ---------591
View Code

  其中通过对银行的存入,手续费,查看3个方法绑定到一个同步块中,实现多个方法绑定的作用,而不影响多线程单独调用各个方法。

     如果synchronized代码块对象是this,就相当于锁定了handler对象,而非bank对象。

      如果synchronized代码块对象是handler的Class类,则对所有的handler对象其作用,就是不论你new 多个handler还是一样可以控制同步化(例如下面结果)。

 1     public static void main(String[] args) {
 2         BankAccess bank = new BankAccess();
 3         BankTreader handler = new BankTreader(bank);
 4         BankTreader handler2 = new BankTreader(bank);
 5         handler.setSaveMoney(500);
 6         Thread t1 = new Thread(handler,"t1");
 7         handler2.setSaveMoney(300);
 8         Thread t2 = new Thread(handler2,"t2");
 9         t1.start();
10         t2.start();
11     }
12 
13 测试结果:
14 ---------495
15 ---------787
View Code

2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

public synchronized test(){*****}  锁住了这个对象即this,等同于  代码块  synchronized(this){*****},但不影响对其它代码块的调用。

因同步方法同步的是对象,如果有两个对象实例则不会影响。因此要注意避免在多线程中创建多个实例。

以下这种例子,就相当于没有加同步代码块。

 1 /**
 2 *
 3 *
 4 */
 5 public class ClassA {
 6       public synchronized void setiTest(int iTest) {
 7 
 8 
 9 ClassA a = new ClassA();
10 ClassA b = new ClassA();
11 Thread t1= new Thread(){
12             @Override
13             public void run() {
14                 a.setiTest(555555555);
15                 System.out.println("-----");
16             }
17             
18         };
19 
20 Thread t1= new Thread(){
21             @Override
22             public void run() {
23                 b.setiTest(555555555);
24                 System.out.println("-----");
25             }
26             
27         };
View Code

3. 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

     因为静态方法属于类对象,而非实例对象。因此静态的synchronized方法作用域是所有的实例对应的类。也就是整个过程只会有一个口,不论你new多少对象。

静态方法不加同步块:
    public static int staticMoney;
    
    private static int sum;
    
    public static void getStaticMoney(){
        sum+=staticMoney;
        System.out.println(sum);
    }

测试口:
    public static void main(String[] args) {
        BankAccess bank = new BankAccess();
        BankTreader handler = new BankTreader(bank);
        BankTreader handler2 = new BankTreader(bank);
        BankTreader handler3 = new BankTreader(bank);
        handler.staticMoney = 100;
        Thread t1 = new Thread(handler,"t1");
        Thread t2 = new Thread(handler2,"t2");
        Thread t3 = new Thread(handler3,"t3");
        t1.start();
        t2.start();
        t3.start();
        try {
            t1.sleep(100);
            t2.sleep(50);
            t3.sleep(0);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
加sleep防止线程同时进行,就相当于一个执行完后,执行另一个。
结果 :
200
200
200
去掉sleep进行:
结果:
运行1次
100
300
200  
运行 2次
100
200
100
运行 3次
200
200
300。。。。。。
会出现结果未知,因为static的1个方法同时被多个线程同时调用尽管是多个对象,但类只有一个,就并发安全问题。


加上synchronized,多次运行结果:
100
200
300
这样就保证了多个线程在运行这个方法时,变为单线程。
View Code

4. 修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

 1     public void handlerBank(){
 2         synchronized(BankAccess.class){
 3             System.out.println(System.currentTimeMillis() + "---A--" + bank.searchMoney());
 4                        //拖延时间
 5             for(int i=0; i <8000000;i++){
 6                 int b= i;
 7             }
 8             bank.saveMoney(saveMoney); //存入
 9             bank.getoutMoney((int)Math.round(bank.searchMoney()*0.01));//收取总额手续费,当然实际银行不会这样
10             System.out.println(System.currentTimeMillis() + "----B-----" + bank.searchMoney()); //查看
11         }
12     }
13 
14 测试方法:
15 public static void main(String[] args) {
16         BankAccess bank = new BankAccess();--构造多个实例
17         BankAccess bank2 = new BankAccess();
18         BankAccess bank3 = new BankAccess();
19         bank.saveMoney(1000);
20         bank2.saveMoney(2000);
21         bank3.saveMoney(4000);
22         BankTreader handler = new BankTreader(bank);--构造多个操作类
23         Thread t1 = new Thread(handler,"t1");
24         BankTreader handler2 = new BankTreader(bank2);
25         Thread t2 = new Thread(handler2,"t2");
26         BankTreader handler3 = new BankTreader(bank3);
27         Thread t3 = new Thread(handler3,"t3");
28         try {
29             t2.sleep(10);
30             t3.sleep(30);
31         } catch (InterruptedException e) {
32             // TODO Auto-generated catch block
33             e.printStackTrace();
34         }
35         t1.start();
36         t2.start();
37         t3.start();
38 
39     }
40 
41 
42 结果:
43 1498732805187---A--1000
44 1498732805193----B-----990
45 1498732805193---A--4000
46 1498732805196----B-----3960
47 1498732805196---A--2000
48 1498732805200----B-----1980   
49 
50 结果分析:
51 对Bank类的操作还是变为线性,当t1,执行时,因执行时间长,因此当t2,t3在不同时间段醒来后,t1中的BankAccess依然没执行完,当执行完后,t3先抢到锁,因此t2,继续等待。 
View Code
 1     public static void main(String[] args) {
 2         BankAccess bank = new BankAccess();
 3         BankAccess bank2 = new BankAccess();
 4         BankAccess bank3 = new BankAccess();
 5         bank.saveMoney(1000);
 6         bank2.saveMoney(2000);
 7         bank3.saveMoney(4000);
 8         BankTreader handler = new BankTreader(bank);
 9         Thread t1 = new Thread(handler,"t1");
10         handler.setBank(bank2);
11         Thread t2 = new Thread(handler,"t2");
12         handler.setBank(bank3);
13         Thread t3 = new Thread(handler,"t3");
14         try {
15             t2.sleep(10);
16             t3.sleep(30);
17         } catch (InterruptedException e) {
18             // TODO Auto-generated catch block
19             e.printStackTrace();
20         }
21         t1.start();
22         t2.start();
23         t3.start();
24 System.out.println("-------------------i am main------");
25     }
26 
27 结果:
28 -------------------i am main------
29 1498733549403---A--4000
30 1498733549408----B-----3960
31 1498733549408---A--3960
32 1498733549411----B-----3920
33 1498733549411---A--3920
34 1498733549414----B-----3881
35 
36 从结果可以看出:
37 尽管bank设置有1000,2000,4000.但因为t1,t2,t3并不是new的时候就执行,而是主程序已经结束了才开始的,此时handler中实际的对象为bank3.因此t1,t2,t3中都是4000的值。也就只有bank3一个对象,此对象在里面进行了3次扣款。
View Code
 1     public static void main(String[] args) {
 2         BankAccess bank2 = new BankAccess();
 3         BankAccess bank1 = new BankAccess();
 4         bank2.saveMoney(4000);
 5         bank1.saveMoney(2000);
 6         BankTreader handler2 = new BankTreader(bank2);
 7         BankTreader handler1 = new BankTreader(bank1);
 8         Thread t1 = new Thread(handler1,"t1");
 9         Thread t2 = new Thread(handler2,"t2");
10         t1.start();
11         t2.start();
12         System.out.println("-------------------i am main------");
13     }
14 
15 结果:
16 -------------------i am main------
17 1498734103614---A--2000
18 1498734103620----B-----1980
19 1498734103620---A--4000
20 1498734103623----B-----3960
21 
22 不同的对象,不同的调用者,但是结果还是线性同步进行的。
View Code

一个线程在访问一个对象的同步方法时,另一个线程可以同时访问这个对象的非同步方法。(只要不是同步方法,就不等对象锁,所以不管这个对象是否有其它线程锁定了,在其它线程访问非同步方法都不需要等同步锁的动作 )

 1 package jquery.test.interview;
 2 
 3 public class ClassA {
 4     private int iTest;
 5     private final static Object obj = new Object();
 6 
 7     public int getiTest() {
 8         System.out.println("---get1--" + System.currentTimeMillis());
 9         //synchronized(obj){
10             for(int i=0;i<555555555;i++){
11                 int b= i;
12             }
13         //}
14         System.out.println("---get2--" + System.currentTimeMillis());
15         return iTest;
16     }
17 
18     public synchronized void setiTest(int iTest) {
19         System.out.println("---set1--" + System.currentTimeMillis());
20         //synchronized(ClassA.class){
21         for(int i=0;i<iTest;i++){
22             int b= i;
23         }
24         //}
25         System.out.println("---set2--" + System.currentTimeMillis());
26         this.iTest = iTest;
27         
28     }
29 
30     
31 }
32 
33 
34 /**
35 测试类
36 **/
37 package jquery.test.interview;
38 
39 public class finalVarTest {
40     
41 
42     public static void main(String[] args) {
43         ClassA a = new ClassA();
44         Thread t1= new Thread(){
45             @Override
46             public void run() {
47                 a.setiTest(555555555);
48                 System.out.println("-----");
49             }
50             
51         };
52         
53         Thread t2= new Thread(){
54             @Override
55             public void run() {
56                 System.out.println("---a.getiTest();--" + a.getiTest());
57                 //a.getiTest();
58             }
59             
60         };
61         //try {
62             t1.start();
63             try {
64                 t2.sleep(1);
65             } catch (InterruptedException e) {
66                 // TODO Auto-generated catch block
67                 e.printStackTrace();
68             }
69             t2.start();
70             //t1.join();
71             //t2.join();
72         //} catch (InterruptedException e) {
73             System.out.println("-join----");
74         //    e.printStackTrace();
75         //}
76         
77         
78         
79         System.out.println("-main----");
80     }
81 
82 }
View Code

一个线程在访问一个对象的同步方法时,另一个线程不能同时访问这个同步方法。

死锁:多个线程多个对象互相调用时,要谨防死锁。一般出现在双重同步代码锁中经常出现。如下面代码:两个对象,两个线程,A,B.A对象调用B对象,B对象调用A对象,这个时候就是各自有把锁,却在等待对方释放锁来执行调用的对象。

/**
 * 这种classB就容易锁住
 */
public synchronized void setiTest(int iTest) {
        System.out.println("---set1--" + System.currentTimeMillis());
        for(int i=0;i<iTest;i++){
            int b= i;
        }
        synchronized(classB){
        for(int i=0;i<iTest;i++){
            int b= i;
        }
        //}
        System.out.println("---set2--" + System.currentTimeMillis());
        this.iTest = iTest;
    }



public static void main(String[] args) throws InterruptedException {
        ClassA c1 = new ClassA();
        ClassA c2 = new ClassA();
        c1.setClassB(c2);
        c2.setClassB(c1);
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                c1.setiTest(50000000);
            }
            
        }, "t1");
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                c2.setiTest(50000000);
            }
            
        }, "t2");
        t1.start();
        t2.start();
        System.out.println("-----Main thread----");
    }

一个线程在访问一个对象的同步方法时,另一个线程不能同时访问其它同步方法。

如果一个线程在访问一个同步方法,则其他的同步方法此时也不允许其它线程访问,因为方法在调用时锁的是调用者对象,因此其它线程要访问其它方法,而其它方法也是同步的话,就需要解锁,而锁被另一个线程的另一个方法所占用,因此只能等待。

破解的方式:就是将锁加在方法中的代码段上,且对象用一个其它的不变对象,这样锁定的就是本方法,不会影响其它方法对锁的调用。

 1     public synchronized int getiTest() {
 2         System.out.println("---get1--" + System.currentTimeMillis());
 3         //synchronized(obj){
 4             for(int i=0;i<555555555;i++){
 5                 int b= i;
 6             }
 7         //}
 8         System.out.println("---get2--" + System.currentTimeMillis());
 9         return iTest;
10     }
11 
12     public synchronized void setiTest(int iTest) {
13         System.out.println("---set1--" + System.currentTimeMillis());
14         //synchronized(ClassA.class){
15         for(int i=0;i<iTest;i++){
16             int b= i;
17         }
18         //}
19         System.out.println("---set2--" + System.currentTimeMillis());
20         this.iTest = iTest;
21     }
22 
23 main方法调用:
24     public static void main(String[] args) {
25         ClassA a = new ClassA();
26         Thread t1 = new Thread(new Runnable(){
27             @Override
28             public void run() {
29                 a.setiTest(600000000);
30             }
31         });
32         Thread t2 = new Thread(new Runnable(){
33             @Override
34             public void run() {
35                 a.getiTest();
36             }
37         });
38         t1.start();
39         t2.start();
40     }
41 
42 结果:
43 ---set1--1498790176386
44 ---set2--1498790176614
45 ---get1--1498790176615
46 ---get2--1498790176827
47 
48 
49 ------------------------------------------------------------------------------
50 修改get方法为代码段形式
51 
52     private final static Object obj = new Object();
53 
54     public int getiTest() {
55         synchronized(obj){
56         System.out.println("---get1--" + System.currentTimeMillis());
57             for(int i=0;i<555555555;i++){
58                 int b= i;
59             }
60             System.out.println("---get2--" + System.currentTimeMillis());
61         }
62         return iTest;
63     }
64 
65 这样get方法的锁对象是obj,而非this。因此不会和set冲突。
66 
67 结果:
68 
69 ---get1--1498790448547
70 ---set1--1498790448547
71 ---get2--1498790448826
72 ---set2--1498790448844
View Code

3.2 volatile 关键字(不稳定的意思)

     volatile用于多个线程共享某一数据时,指示读取数据从最新的主存中查找数据,指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 

 volatile不保证原子操作,很容易读到脏数据。多个线程中共有变量,在不使用同步块时可以考虑用volatile关键字。

   因回写的速度较快,因此大量数据的测试,才能看出结果。

  1 private volatile String str = "abc";
  2     public static void main(String[] args) throws InterruptedException, ExecutionException {
  3         finalVarTest fv = new finalVarTest();
  4         Thread t1 = new Thread(new Runnable(){
  5             @Override
  6             public void run() {
  7                 try {
  8                 for(int i=0;i<100;i++){
  9                     fv.setStr("cde" + i);
 10                     Thread.sleep(10);
 11                 }
 12                     System.out.println("---01-before--1-" + fv.getStr());
 13                 } catch (InterruptedException e) {
 14                     // TODO Auto-generated catch block
 15                     e.printStackTrace();
 16                 }
 17             }
 18         });
 19         Thread t2 = new Thread(new Runnable(){
 20             @Override
 21             public void run() {
 22                 try {
 23                     for(int i=0;i<100;i++){
 24                         Thread.sleep(10);
 25                         System.out.println("---02-before--2-" + fv.getStr());
 26                     }
 27                     
 28                 } catch (InterruptedException e) {
 29                     // TODO Auto-generated catch block
 30                     e.printStackTrace();
 31                 }
 32                 
 33             }
 34         });
 35         System.out.println("I main 1........");
 36         t1.start();
 37         t2.start();
 38         System.out.println("I main 2........");
 39     }
 40     public String getStr() {
 41         return str;
 42     }
 43     public void setStr(String str) {
 44         this.str = str;
 45     }
 46 
 47 结果:
 48 ---当使用volatile时,保证了100条数据t2线程获取到的都是顺序的,从0-99.
 49 ---02-before--2-cde0
 50 ---02-before--2-cde1
 51 ---02-before--2-cde2
 52 ---02-before--2-cde3
 53 ---02-before--2-cde4
 54 ---02-before--2-cde5
 55 ---02-before--2-cde6
 56 ---02-before--2-cde7
 57 ---02-before--2-cde8
 58 ---02-before--2-cde9
 59 ---02-before--2-cde10
 60 ---02-before--2-cde11
 61 ---02-before--2-cde12
 62 ---02-before--2-cde13
 63 ---02-before--2-cde14
 64 ---02-before--2-cde15
 65 ---02-before--2-cde16
 66 ---02-before--2-cde17
 67 ---02-before--2-cde18
 68 ---02-before--2-cde19
 69 ---02-before--2-cde20
 70 ---02-before--2-cde21
 71 ---02-before--2-cde22
 72 ---02-before--2-cde23
 73 ---02-before--2-cde24
 74 ---02-before--2-cde25
 75 ---02-before--2-cde26
 76 ---02-before--2-cde27
 77 ---02-before--2-cde28
 78 ---02-before--2-cde29
 79 ---02-before--2-cde30
 80 ---02-before--2-cde31
 81 ---02-before--2-cde32
 82 ---02-before--2-cde33
 83 ---02-before--2-cde34
 84 ---02-before--2-cde35
 85 ---02-before--2-cde36
 86 ---02-before--2-cde37
 87 ---02-before--2-cde38
 88 ---02-before--2-cde39
 89 ---02-before--2-cde40
 90 ---02-before--2-cde41
 91 ---02-before--2-cde42
 92 ---02-before--2-cde43
 93 ---02-before--2-cde44
 94 ---02-before--2-cde45
 95 ---02-before--2-cde46
 96 ---02-before--2-cde47
 97 ---02-before--2-cde48
 98 ---02-before--2-cde49
 99 ---02-before--2-cde50
100 ---02-before--2-cde51
101 ---02-before--2-cde52
102 ---02-before--2-cde53
103 ---02-before--2-cde54
104 ---02-before--2-cde55
105 ---02-before--2-cde56
106 ---02-before--2-cde57
107 ---02-before--2-cde58
108 ---02-before--2-cde59
109 ---02-before--2-cde60
110 ---02-before--2-cde61
111 ---02-before--2-cde62
112 ---02-before--2-cde63
113 ---02-before--2-cde64
114 ---02-before--2-cde65
115 ---02-before--2-cde66
116 ---02-before--2-cde67
117 ---02-before--2-cde68
118 ---02-before--2-cde69
119 ---02-before--2-cde70
120 ---02-before--2-cde71
121 ---02-before--2-cde72
122 ---02-before--2-cde73
123 ---02-before--2-cde74
124 ---02-before--2-cde75
125 ---02-before--2-cde76
126 ---02-before--2-cde77
127 ---02-before--2-cde78
128 ---02-before--2-cde79
129 ---02-before--2-cde80
130 ---02-before--2-cde81
131 ---02-before--2-cde82
132 ---02-before--2-cde83
133 ---02-before--2-cde84
134 ---02-before--2-cde85
135 ---02-before--2-cde86
136 ---02-before--2-cde87
137 ---02-before--2-cde88
138 ---02-before--2-cde89
139 ---02-before--2-cde90
140 ---02-before--2-cde91
141 ---02-before--2-cde92
142 ---02-before--2-cde93
143 ---02-before--2-cde94
144 ---02-before--2-cde95
145 ---02-before--2-cde96
146 ---02-before--2-cde97
147 ---02-before--2-cde98
148 ---02-before--2-cde99
149 --当不使用volatile时,不能保证t2取到的数据都是齐的。
150 ---02-before--2-cde1
151 ---02-before--2-cde1
152 ---02-before--2-cde3
153 ---02-before--2-cde3
154 ---02-before--2-cde5
155 ---02-before--2-cde5
156 ---02-before--2-cde6
157 ---02-before--2-cde8
158 ---02-before--2-cde8
159 ---02-before--2-cde9
160 ---02-before--2-cde10
161 ---02-before--2-cde11
162 ---02-before--2-cde12
163 ---02-before--2-cde13
164 ---02-before--2-cde14
165 ---02-before--2-cde15
166 ---02-before--2-cde16
167 ---02-before--2-cde17
168 ---02-before--2-cde18
169 ---02-before--2-cde19
170 ---02-before--2-cde20
171 ---02-before--2-cde21
172 ---02-before--2-cde22
173 ---02-before--2-cde23
174 ---02-before--2-cde24
175 ---02-before--2-cde25
176 ---02-before--2-cde26
177 ---02-before--2-cde27
178 ---02-before--2-cde29
179 ---02-before--2-cde29
180 ---02-before--2-cde30
181 ---02-before--2-cde32
182 ---02-before--2-cde32
183 ---02-before--2-cde33
184 ---02-before--2-cde34
185 ---02-before--2-cde35
186 ---02-before--2-cde36
187 ---02-before--2-cde37
188 ---02-before--2-cde38
189 ---02-before--2-cde40
190 ---02-before--2-cde40
191 ---02-before--2-cde41
192 ---02-before--2-cde42
193 ---02-before--2-cde43
194 ---02-before--2-cde44
195 ---02-before--2-cde45
196 ---02-before--2-cde46
197 ---02-before--2-cde47
198 ---02-before--2-cde48
199 ---02-before--2-cde49
200 ---02-before--2-cde51
201 ---02-before--2-cde51
202 ---02-before--2-cde52
203 ---02-before--2-cde53
204 ---02-before--2-cde54
205 ---02-before--2-cde55
206 ---02-before--2-cde56
207 ---02-before--2-cde57
208 ---02-before--2-cde58
209 ---02-before--2-cde59
210 ---02-before--2-cde60
211 ---02-before--2-cde61
212 ---02-before--2-cde62
213 ---02-before--2-cde63
214 ---02-before--2-cde64
215 ---02-before--2-cde66
216 ---02-before--2-cde67
217 ---02-before--2-cde68
218 ---02-before--2-cde69
219 ---02-before--2-cde70
220 ---02-before--2-cde71
221 ---02-before--2-cde72
222 ---02-before--2-cde73
223 ---02-before--2-cde74
224 ---02-before--2-cde75
225 ---02-before--2-cde76
226 ---02-before--2-cde77
227 ---02-before--2-cde78
228 ---02-before--2-cde79
229 ---02-before--2-cde80
230 ---02-before--2-cde81
231 ---02-before--2-cde82
232 ---02-before--2-cde83
233 ---02-before--2-cde84
234 ---02-before--2-cde85
235 ---02-before--2-cde86
236 ---02-before--2-cde87
237 ---02-before--2-cde88
238 ---02-before--2-cde89
239 ---02-before--2-cde90
240 ---02-before--2-cde91
241 ---02-before--2-cde92
242 ---02-before--2-cde93
243 ---02-before--2-cde94
244 ---02-before--2-cde95
245 ---02-before--2-cde96
246 ---02-before--2-cde97
247 ---02-before--2-cde98
248 ---02-before--2-cde99
View Code

 

4.线程状态

1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程中sleep和wait的区别:
   1. sleep和join是Thread类的方法,而wait和notify,notifyAll是Object类的方法。不过他们都是native修饰的。
           2. sleep如果握有锁,则一直持有不会释放。而wait会释放锁,进入等待,需要notify才可以唤醒。
           3. sleep被打断会抛出异常,需要捕获处理,而wait不会抛出异常。
           4. wait和notify要运行在syncronized中,而sleep是在那写的,作用于那。
          

sleep:

            1. sleep作用的是运行的真实线程Thread,而非Thread线程的类。
            2.  写在那地方的作用域内,对那个Thread起作用。
            3.  Thread.sleep和Thread.currentThread.sleep 在作用于Thread类及子类时,是等效的。在作用于实现Runnable接口的类时,只能通过Thread.currentThread.sleep才可以起作用。
   

   

           4. sleep作用为当前的作用域,而非当前对象。

1 System.out.println("I main 1........");
2 t1.start();
3 t1.sleep(6000);       --在主线程中加sleep会作用的主线程上。sleep是在哪加作用到哪地方
4 System.out.println("I main 2........");
5 
6 结果:
7 I main 1........
8 ---01----Thread-0
9 I main 2........

 

interrupt:

               1. 打断正在Sleep的线程,让其赶紧执行。但是会在sleep中抛出一个innterruptException异常,如果没有sleep,则不会报错。

 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         Thread t1 = new Thread(new Runnable(){
 3             @Override
 4             public void run() {
 5                 try {
 6                     Thread.sleep(1000);
 7                 } catch (InterruptedException e) {
 8                     System.out.println("--谁把我打断了----");
 9                 }
10                 System.out.println("---01----" + Thread.currentThread().getName());
11             }
12         });
13         System.out.println("I main 1........");
14         t1.start();
15         //Thread.sleep(100);
16         t1.interrupt();
17         System.out.println("I main 2........");
18     }
19 
20 结果:
21 I main 1........
22 I main 2........
23 --谁把我打断了----
24 ---01----Thread-0
Interrupt

 join:

           1. join和sleep一样,都是Thread类的方法。join作用是让“主线程”等待“子线程”结束之后才能继续运行。即当前线程挂起,等子线程运行完后,再继续主线程。

 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         Thread t1 = new Thread(new Runnable(){
 3             @Override
 4             public void run() {
 5                 try {
 6                 
 7                     Thread.sleep(1000);
 8                     System.out.println("---01-before--1-");
 9                 } catch (InterruptedException e) {
10                     e.printStackTrace();
11                 }
12             }
13         });
14         System.out.println("I main 1........");
15         t1.start();
16         t1.join();
17         System.out.println("I main 2........");
18     }
19 
20 --------------------------------------------------------------
21 结果:
22 I main 1........
23 ---01-before--1-abc
24 I main 2........
View Code

       join(long millis);    join(long millis, int nanos);   --设置时间

 yeald(屈服):  Thread.yield()

        1.yeald将当前执行的线程,重新打回到执行队列中,重新抢占执行,因此有可能会多次执行。不过在优先级中同级优先级的队列是有可能同时执行,但不同优先级则可能不再执行。
  • Yield是一个静态的原生(native)方法
  • Yield告诉当前正在执行的线程把运行机会交给线程池中拥有相同优先级的线程。
  • Yield不能保证使得当前正在运行的线程迅速转换到可运行的状态。   //不能保证立即交付,因cpu中有可能已经存在正在执行的。
  • 它仅能使一个线程从运行状态转到可运行状态,而不是等待或阻塞状态
 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         Thread producer = new Thread(new Runnable(){
 3             @Override
 4             public void run() {
 5                 for(int i=0;i<15;i++){
 6                     System.out.println("---producer--1-");
 7                 }
 8                 
 9             }
10         });
11         Thread customer = new Thread(new Runnable(){
12             @Override
13             public void run() {
14                 for(int i=0;i<15;i++){
15                     System.out.println("---customer--2-");
16                 }
17             }
18         });
19         System.out.println("I main 1........");
20         //producer.setPriority(Thread.MIN_PRIORITY);
21         //customer.setPriority(Thread.MAX_PRIORITY);
22         producer.start();
23         customer.start();
24         
25         System.out.println("I main 2........");
26     }
27 
28 -------------------------------------------------------------
29 不带优先级时: 打印中customer 和productor交叉出现。
30 带优先级时,先打印customer后打印productor
View Code

 

     yield后customer的优先权就转出来,这时候productor就有了执行的机会。但customer比productor有高优先级,因此还是会有customer在中间执行。

 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         Thread producer = new Thread(new Runnable(){
 3             @Override
 4             public void run() {
 5                 for(int i=0;i<15;i++){
 6                     System.out.println("---producer--1-");
 7                 }
 8                 
 9             }
10         });
11         Thread customer = new Thread(new Runnable(){
12             @Override
13             public void run() {
14                 for(int i=0;i<15;i++){
15                     if(i>8){                        //当执行8个时让渡
16                         Thread.yield();
17                     }
18                     System.out.println("---customer--2-");
19                 }
20             }
21         });
22         System.out.println("I main 1........");
23         producer.setPriority(Thread.MIN_PRIORITY);
24         customer.setPriority(Thread.MAX_PRIORITY);
25         producer.start();
26         customer.start();
27         System.out.println("I main 2........");
28     }
29 
30 ---------------------------------------------------------------------------
31 结果:
32 ---customer--2-0
33 ---producer--1-0
34 ---customer--2-1
35 ---producer--1-1
36 ---customer--2-2
37 ---producer--1-2
38 ---customer--2-3
39 ---customer--2-4
40 ---customer--2-5
41 ---customer--2-6
42 ---customer--2-7
43 ---customer--2-8
44 ---customer--2-9
45 ---producer--1-3
46 ---producer--1-4
47 ---producer--1-5
48 ---producer--1-6
49 ---producer--1-7
50 ---producer--1-8
51 ---producer--1-9
52 ---producer--1-10
53 ---producer--1-11
54 ---producer--1-12
55 ---producer--1-13
56 ---producer--1-14
57 ---customer--2-10
58 ---customer--2-11
59 ---customer--2-12
60 ---customer--2-13
61 ---customer--2-14
View Code

 

wait和notify,notifyAll

       wait() 与 notify/notifyAll() 是Object类的方法,在执行两个方法时,要先获得锁。因此他们大多都是写在synchronized中。

      wait和notify的执行顺序不能错,不然先notify后wait则程序等待。

      在main方法中写   customer.wait();报错 java.lang.IllegalMonitorStateException,因为wait和notify要拿到锁才可以,此时因没有拿到锁所以报错。

     且wait和notify必须作用于同一个对象。要不然不起作用。

 1 package jquery.test.interview;
 2 
 3 public class ClassA {
 4     private int iTest;
 5     private final static Object obj = new Object();
 6     private ClassA classB;
 7 
 8     public ClassA getClassB() {
 9         return classB;
10     }
11 
12     public void setClassB(ClassA classB) {
13         this.classB = classB;
14     }
15 
16     public  int getiTest() throws InterruptedException {
17         System.out.println("---get1--" + System.currentTimeMillis());
18         synchronized(obj){
19             obj.wait();
20             for(int i=0;i<555555555;i++){
21                 int b= i;
22             }
23             System.out.println("---get2--" + System.currentTimeMillis());
24         }
25         return iTest;
26     }
27 
28     public synchronized void setiTest(int iTest) {
29         System.out.println("---set1--" + System.currentTimeMillis());
30         for(int i=0;i<iTest;i++){
31             int b= i;
32         }
33         System.out.println("---set2--" + System.currentTimeMillis());
34         this.iTest = iTest;
35 
36     }
37 }
ClassA
 1         ClassA ca = new ClassA();
 2         Thread t1= new Thread(){
 3             @Override
 4             public void run() {
 5                 ca.setiTest(50000);
 6             };
 7         };
 8         
 9         Thread t2= new Thread(){
10             @Override
11             public void run() {
12                 try {
13                     ca.getiTest();
14                 } catch (InterruptedException e) {
15                     // TODO Auto-generated catch block
16                     e.printStackTrace();
17                 }
18             };
19         };
20               t1.start();
21               t2.start();
22 
23 
24 ------------------------------------------------------------------------------
Test Main

 

结果: t2执行wait后,释放了锁,进入等待状态,但是没有唤醒的线程来重新唤醒,因此程序处于一直运行等待中,而未结束,除非使用interrupt,或者stop强行停止。

  多用于生产者和消费者模式: 

 1 package jquery.test.interview;
 2 
 3 import java.util.Vector;
 4 
 5 public class Productor<T> implements Runnable {
 6     
 7     private volatile Vector<T> v;
 8     
 9     public Productor(Vector<T> v){
10          this.v = v;
11     }
12     
13     /**
14      * 生产产品
15      * @return
16      */
17     public void createProduct(){
18         synchronized(v){
19             while(true){
20                 System.out.println("库存产品数....1.." + v.size());
21                 if(v.isEmpty() || v.size() < 3){
22                     System.out.println("库存紧张,开始生产......");
23                     v.add((T)"product1.....");
24                     v.add((T)"product2.....");
25                     v.add((T)"product3.....");
26                     v.add((T)"product4.....");
27                     v.add((T)"product5.....");
28                 }
29                 //开始等待
30                 try {
31                     System.out.println("库存产品数...2..." + v.size());
32                     v.notifyAll();
33                     v.wait();
34                 } catch (InterruptedException e) {
35                     e.printStackTrace();
36                 }
37                 
38             }
39         }
40     }
41 
42     @Override
43     public void run() {
44         createProduct();
45     }
46 
47 }
Productor

 

 1 package jquery.test.interview;
 2 
 3 import java.util.Vector;
 4 
 5 public class Customer<T> implements Runnable {
 6     
 7     private volatile Vector<T> vector;
 8     
 9     public Customer(Vector<T> vector){
10         this.vector = vector;
11     }
12     
13     public  void getProduct(){
14         synchronized(vector){
15             while(true){
16                 if(null == vector || vector.isEmpty()){
17                     try {
18                         System.out.println("--没有产品等待中.....");
19                         vector.wait();
20                     } catch (InterruptedException e) {
21                         e.printStackTrace();
22                     }
23                 }else{
24                     System.out.println("--获取产品使用....." + vector.get(0));
25                     vector.remove(0);
26                     vector.notify();
27                 }
28             }
29         }
30     }
31 
32     @Override
33     public void run() {
34         getProduct();
35     }
36 
37 }
Customer
 1 测试及结果:
 2 public static void main(String[] args) throws InterruptedException, ExecutionException {
 3         Vector<String> product = new Vector<String>();
 4         ExecutorService pool = Executors.newCachedThreadPool();
 5         Productor<String> proc = new Productor<String>(product);
 6         pool.submit(proc);
 7         for(int i =0;i<5;i++){
 8             Customer<String> cus = new Customer<String>(product);
 9             pool.submit(cus);
10         }
11     }
12 
13 -------------------------------------------------------------------------------
14 库存产品数....1..0
15 库存紧张,开始生产......
16 库存产品数...2...5
17 --获取产品使用.....product1.....
18 --获取产品使用.....product2.....
19 --获取产品使用.....product3.....
20 --获取产品使用.....product4.....
21 --获取产品使用.....product5.....
22 --没有产品等待中.....
23 库存产品数....1..0
24 库存紧张,开始生产......
25 库存产品数...2...5
26 --获取产品使用.....product1.....
27 --获取产品使用.....product2.....
28 --获取产品使用.....product3.....
29 --获取产品使用.....product4.....
30 --获取产品使用.....product5.....
31 --没有产品等待中.....
32 --没有产品等待中.....
33 --没有产品等待中.....
34 --没有产品等待中.....
35 库存产品数....1..0
36 库存紧张,开始生产......
37 库存产品数...2...5
38 --获取产品使用.....product1.....
39 --获取产品使用.....product2.....
40 --获取产品使用.....product3.....
41 --获取产品使用.....product4.....
42 --获取产品使用.....product5.....
43 --没有产品等待中.....
44 库存产品数....1..0
45 库存紧张,开始生产......
46 库存产品数...2...5
47 --获取产品使用.....product1.....
48 --获取产品使用.....product2.....
49 --获取产品使用.....product3.....
50 --获取产品使用.....product4.....
51 --获取产品使用.....product5.....
52 --没有产品等待中.....
53 --没有产品等待中.....
54 --没有产品等待中.....
55 --没有产品等待中.....
56 --没有产品等待中.....
57 库存产品数....1..0
58 库存紧张,开始生产......
59 库存产品数...2...5
60 --获取产品使用.....product1.....
61 --获取产品使用.....product2.....
62 --获取产品使用.....product3.....
63 --获取产品使用.....product4.....
64 --获取产品使用.....product5.....
65 --没有产品等待中.....
66 --没有产品等待中.....
67 --没有产品等待中.....
测试

新建线程:

1.new Thread

    public static void main(String[] args) {
        ClassA a = new ClassA();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                //TODO
                System.out.println("------Thread  t1----");
                a.getiTest();
            }
        };
        t1.start();
        System.out.println("-----Main thread----");
    }

    结果:------------------------------------------------------------

 

线程通过run()方法执行代码,因此一定要override run()方法。线程通过start()方法进入线程队列排队等待cpu的调动。因此一定要在启用时使用start()方法。Thread是个类,因此run方法不会自动出来,要自己复写。
t1.setPriority(newPriority); // 线程可以设置优先级

优先级可以用从1到10的范围指定。10表示最高优先级,1表示最低优先级,5是普通优先级。也可用 MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY来设定优先级

2. new Runnable或者实现runnable接口

   new Thread(Runnable runnable, String name);    //实现runnable接口的类,name为给线程起的名字
    public static void main(String[] args) {
        ClassA a = new ClassA();
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                //TODO
                System.out.println("------Runnable  t1----");
                a.getiTest();
            }
        });
        t1.start();
        System.out.println("-----Main thread----");
    }

   实现接口的方式:

/**
 *实现Runnable接口
 */
public class BankTreader implements Runnable {

    @Override
    public void run() {
        handlerBank();
    }


-----------------------------------------------
    public static void main(String[] args) {
        BankTreader b1 = new BankTreader();
        Thread t1 = new Thread(b1, "t1");
        t1.start();
        System.out.println("-----Main thread----");
    }

 

实现接口的方式会束缚: 多线程调用代码被固定死。  比如在BankThreader中 只能调用 handlerBank();而不能调用其它方法。而第一种就不牵扯这个问题,在需要的时候构造Runnable,传入需要调用方法。

3. 线程池

  有这样1个场景,现在有100个数据需要处理,如果我们为其开辟new 100个线程,一次开销太大,同时cpu也不可能同时消化的了,从资源占有和性能上反而是种浪费。因此这就需要合理的开辟线程,假设我们开辟10个线程,这样每个线程去处理10笔数,这种就解决了性能和资源占有的问题。但是线程的执行不是线性的,不是A线程执行1个后,B线程执行1个,然后。。。。。,而是无序的有可能C线程都执行了2笔数据但A线程1笔都没有抢到。因此,为了合理的调度10个线程,使其尽量都满负荷的完成任务。就引入了线程池管理。

       ThreadPoolExecutor:

ThreadPoolExecutor

  详细的工作原理参考:(深入理解Java之线程池)http://www.cnblogs.com/dolphin0520/p/3932921.html

       ThreadPoolExecutor 主要方法说明:

  execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。

  submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果(Future相关内容将在下一篇讲述)。

  shutdown()和shutdownNow()是用来关闭线程池的。

      线程池使用:

     Java通过Executors提供四种线程池,分别为:
      newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。这种是动态线程数的线程池,适合处理量不是特别大的线程数,比如100个数据就会造成在开始运行时开辟过多线程,但5个或10个时就负载小。

      newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。这种和第一种相反,适合大量数据长时计算,在保证运算速率时,又不挤兑其它程序的运行。
      newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。这种是定时运行,延迟运行程序用,定时任务这种就比较适合。
      newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。这是线性运行,一次保证只有一个运行,且必须依照顺序进行,不会出现无序状况。

创建连接池,通过utils下的Executors创建连接池,java监控(C:\Program Files (x86)\Java\jdk1.8.0_121\bin\jconsole.exe)执行结果。

Thread.sleep(100);//线程睡眠

Thread.currentThread().getName();  //获取当前运行thread的名字

线程池用完要关闭,es.shutdown();

newCachedThreadPool

 1     public static void main(String[] args) throws InterruptedException {
 2         Thread.sleep(2000);  //去监控器找到这个java,启用监控
 3         Executor ex = Executors.newFixedThreadPool(10);
 4         for(int i=0; i < 100; i++){
 5             final int fi = i;
 6             ex.execute(new Runnable(){
 7                 @Override
 8                 public void run() {
 9                     try {
10                         Thread.sleep(100);  //延缓,使得线程不能及时结束
11                     } catch (InterruptedException e) {
12                         e.printStackTrace();
13                     }
14                     System.out.println("####" + Thread.currentThread().getName() + "------------" + fi);
15                 }
16             });
17         }
18     }
newFixedThreadPool  

 1 // 延迟执行    
 2 public static void main(String[] args) throws InterruptedException {
 3         ScheduledExecutorService ex = Executors.newScheduledThreadPool(8);
 4         for(int i=0; i < 10; i++){
 5             final int fi = i;
 6             ex.schedule(new Runnable(){   //延迟执行
 7                 @Override
 8                 public void run() {
 9                 
10                     System.out.println("####" + System.currentTimeMillis() + "------------" + fi);
11                 }
12             }, 2, TimeUnit.SECONDS);    //延迟2秒执行
13         }
14     }
15 
16 // 定时执行
17 public static void main(String[] args) throws InterruptedException {
18         ScheduledExecutorService ex = Executors.newScheduledThreadPool(8);
19         for(int i=0; i < 2; i++){
20             final int fi = i;
21             ex.scheduleAtFixedRate(new Runnable(){   //定时执行
22                 @Override
23                 public void run() {
24                 
25                     System.out.println("####" + System.currentTimeMillis() + "------------" + fi);
26                 }
27             }, 0, 2, TimeUnit.SECONDS);    //每次隔2秒执行
28         }
29     }
newScheduledThreadPool
newSingleThreadExecutor 
其实newSingleThreadExecutor调用的是fixedThreadExecutor,指定线程数为1.

 

4. Callable<V> 接口,Future<V> 接口,FutureTask实现类

     因实现Runnable和继承Thread方式创建的线程都是没有回调函数的,也就是不知道什么时候结束的,哪一个结束了等。没法满足对线程结束时的管理操作。

     Java SE 5.0引入的Callable和Future,可以构建带回调函数的线程接口。

     Callable<V> 带有回调方法的接口V call()。Runnable接口void   run()方法。

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

   Future<V>接口是用来获取异步计算结果的,可判断是否线程执行结束,获取结果,取消等操作 。

因此,这两个要在一起连用才可以获取多线程的结果。

cancel方法中的参数params ,如果为true则试图中断当前的操作,返回true,false则等待当前的操作完成返回false.

get()可阻塞当前主线程,等待子线程完成后进行。

isDone可判断子线程是否已经结束,可用 while(!f.isDone){system.out.println("还没完还没完")}等待并检查是否完成。

 FutureTask实现Runnable和Future接口的实现类,但没有实现Callable接口,callable要自己创建实现类,通过FutureTask构造器传入使用。

public interface RunnableFuture<V> extends Runnable, Future<V> { 

public class FutureTask<V> implements RunnableFuture<V> { FutureTask(Callable<V> callable) FutureTask(Runnable runnable, V result)
 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         String  result = "1234";
 3         FutureTask<String> ft0 = new FutureTask<String>(new Runnable(){
 4             @Override
 5             public void run() {
 6                 try {
 7                     Thread.sleep(1);
 8                 } catch (InterruptedException e) {
 9                     e.printStackTrace();
10                 }
11                 System.out.println("-------runnable----");
12             }}, result);
13         
14         
15         FutureTask<String> ft = new FutureTask<String>(new Callable<String>(){
16             @Override
17             public String call() throws Exception {
18                 System.out.println("-------call----");
19                 return "hello:---call";
20             }
21         });
22         Thread t1 = new Thread(ft);
23         t1.start();
24         Thread t0 = new Thread(ft0);
25         t0.start();
26         if(ft.get() != null){  //主线程在此处会等待其它线程完成,获取结果
27             System.out.println(ft.get());
28         }
29         while(!ft0.isDone()){
30             System.out.println("----还没结束----");
31         }
32         System.out.println(ft0.get());
33     }
FutureTask

 

 线程池支持Callable接口和Future接口,因此线程调用最好用线程池去做。
 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         ExecutorService es = Executors.newFixedThreadPool(5);
 3         List<Future<String>> list = new ArrayList<Future<String>>();
 4         for(int i=0;i<10;i++){
 5             final int fi = i;
 6             Future<String> fu = es.submit(new Callable<String>(){
 7                 @Override
 8                 public String call() throws Exception {
 9                     System.out.println("---ok  call--" + fi);
10                     return "I'm callable----" + fi;
11                 }
12             });
13             list.add(fu);
14         }
15         es.shutdown();
16         // 结果输出
17         for(Future<String> fu : list){
18             System.out.println(fu.get());
19         }
20     }
Future和Callable

 最后用FutureTask来实现连接池调用

 1 public static void main(String[] args) throws InterruptedException, ExecutionException {
 2         ExecutorService es = Executors.newFixedThreadPool(5);
 3         List<FutureTask<String>> list = new ArrayList<FutureTask<String>>();
 4         for(int i=0;i<10;i++){
 5             final int fi = i;
 6             FutureTask<String> ft = new FutureTask<String>(new Callable<String>(){
 7                 @Override
 8                 public String call() throws Exception {
 9                     System.out.println("---ok  call--" + fi);
10                     return "I'm callable----" + fi;
11                 }
12             });
13             es.submit(ft);
14             list.add(ft);
15         }
16         es.shutdown();
17         // 结果输出
18         for(Future<String> fu : list){
19             System.out.println(fu.get());
20         }
21     }
View Code

 参考:

Java中的多线程你只要看这一篇就够了http://www.cnblogs.com/wxd0108/p/5479442.html

Java多线程学习(吐血超详细总结)http://www.mamicode.com/info-detail-517008.html

深入理解Java之线程池)http://www.cnblogs.com/dolphin0520/p/3932921.html

Java四种线程池的使用)http://cuisuqiang.iteye.com/blog/2019372

转载于:https://www.cnblogs.com/DennyZhao/p/7094093.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值