实现线程的第三种方式

1 实现线程前两种方式的缺点

1) 没有返回值

2) 不支持泛型

3) 异常必须处理

2.实现多线程的第三种方式

实现 Callable 接口,重写 call 方法

Callable 功能更加强大:

1) Future 接 口 位 于 java.util.concurrent 包 中 ,可 以 对 具 体Runnable、Callable 任务的执行结果进行取消(cancel 方法,尝试取消执行此任务)、查询是否完成(isDone 方法)、

取结果(get 方法,等待完成,然后检索其结果)等。  future 将来

2) FutrueTask 是 Futrue 接口的唯一的实现类

3) FutureTask 同时实现了 Runnable, Future 接口。它既可以作为 Runnable 被线程执行,又可以作为 Future 得到Callable 的返回值

创建一个实现Callable接口的类

 1 import java.util.concurrent.Callable;
 2 
 3 public class MyCallable implements Callable<String> { //callable能使用泛型
 4 
 5     @Override
 6     public String call() throws Exception { //可以返回结果 抛异常
 7         String [] str={"apple","banana","orange","pear","grape"};
 8         int index=(int)(Math.random()*5); //random 随机返0到0.99 此处*5后转int则为随机返0到4
 9         return str[index];
10     }
11 }

测试类

 1 import java.util.concurrent.ExecutionException;
 2 import java.util.concurrent.FutureTask;
 3 
 4 public class Test {
 5     public static void main(String[] args) throws InterruptedException, ExecutionException {
 6         //(1)创建任务
 7         MyCallable call=new MyCallable();
 8         //(2)交给任务管理 
 9         /**任务管理器是一个实现类,实现了RunnableFutrue接口,
10          * RunnableFutrue是Futrue与Runnable接口的子接口*/
11         FutureTask<String> task=new FutureTask<>(call); //可以看成是Runnable接口的实现类
12         //创建代理类并启动线程
13         Thread t=new Thread(task);
14         t.start();
15         System.out.println("获取结果:"+task.get());
16         //判断任务是否执行完成
17         System.out.println("任务是否执行完成:"+task.isDone());
18     }
19 }

----------------------------------------------------------------------------------------------------------

线程同步的第三种方法

Lock 锁:对需要上锁的地方上锁

1) JDK1.5 后新增的功能

2) 与 Synchronized 相比,Lock 可提供多种锁方案,更灵活

3) Java.util.concurrent.locks 中的 Lock 是一个接口,它的实现类是一个 Java 类,而不是作为语言的特性(关键字)来实现

注意:如果同步代码有异常,要将 unLock()放到 finally 中

步骤

1) 创建 Lock 对象
2) 调用 lock()方法上锁
3) 调用 unlock()方法解锁

 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3 
 4 public class CountRunnable implements Runnable {
 5     private int count=0;//默认值
 6     //创建一个Lock对象
 7     Lock lock=new ReentrantLock();  //Reentrant 可重入
 8     @Override
 9     public void run() {
10         for(int i=0;i<10;i++){
11             //synchronized (this) {
12             try{
13                 lock.lock();//加锁
14                 count++;
15                 try {
16                     Thread.sleep(300);
17                 } catch (InterruptedException e) {
18                     // TODO Auto-generated catch block
19                     e.printStackTrace();
20                 }
21                 System.out.println(Thread.currentThread().getName()+"执行操作:count="+count);
22                 
23             }finally{
24                 //解锁
25                 lock.unlock();
26             }
27             }
28             //}
29     }
30 }
View Code
 1 public class Test {
 2     public static void main(String[] args) {
 3         CountRunnable cr=new CountRunnable();
 4         //代理类的对象
 5         Thread t1=new Thread(cr,"A");
 6         Thread t2=new Thread(cr,"B");
 7         Thread t3=new Thread(cr,"C");
 8         
 9         t1.start();
10         t2.start();
11         t3.start();
12         
13     }
14 }
View Code

---------------------------------------------------------------------------------------------------------------

Lock 与 synchronized 的区别

1) Lock 是 显 示 锁 (手 动 开 启 和 关 闭 锁 ,别 忘 关 闭锁),synchronized 是隐式锁

2) Lock 只有代码块锁,synchronized 有代码块锁和方法锁

3) 使用 Lock 锁,JVM 将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)

4) Lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

lock()方法会对 Lock 实例对象进行加锁,因此所有对该对象调用 lock()方法的线程都会被阻塞,直到该 Lock 对象的 unlock()方法被调用

原文地址:https://www.cnblogs.com/bfcs/p/10825660.html