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 }
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 }
---------------------------------------------------------------------------------------------------------------
Lock 与 synchronized 的区别
1) Lock 是 显 示 锁 (手 动 开 启 和 关 闭 锁 ,别 忘 关 闭锁),synchronized 是隐式锁
2) Lock 只有代码块锁,synchronized 有代码块锁和方法锁
3) 使用 Lock 锁,JVM 将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)
4) Lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock()方法会对 Lock 实例对象进行加锁,因此所有对该对象调用 lock()方法的线程都会被阻塞,直到该 Lock 对象的 unlock()方法被调用