多线程---7

1.线程池补充

  • 快捷方式创建线程池,为什么不能用?
    1. 不能使用无边界的阻塞队列——生产速度(提交任务)如果快于消费速度(线程执行速度),阻塞队列存放的任务会越来越多,导致OOM,整个进程换掉。
    2. 即便指定了有边界的阻塞队列,还需要指定拒绝策略(一般是自定义),一般是记录任务(日志,数据库,其他)

2.死锁

class Pen {
	private String pen = "笔" ; 
	public String getPen() {
		return pen;
	}
}
class Book {
	private String book = "本" ; 
	public String getBook() {
		return book;
	}
}
public class DeadLock {
	private static Pen pen = new Pen() ; 
	private static Book book = new Book() ; 
	public static void main(String[] args) {
		new DeadLock().deadLock();
	}
	public void deadLock() {
		Thread thread1 = new Thread(new Runnable() { // 笔线程
			@Override
			public void run() {
				try {
					synchronized (pen) {
						System.out.println(Thread.currentThread()+" :我有笔,我就不给你");
						Thread.sleep(1000);
						synchronized (book) {
							System.out.println(Thread.currentThread()+" :把你的本给我!");
						}
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		},"Pen") ; 
		
		Thread thread2 = new Thread(new Runnable() { // 本子线程
			@Override
			public void run() {
				try {
					synchronized (book) {
						System.out.println(Thread.currentThread()+" :我有本子,我就不给你!");
						Thread.sleep(1000);
						synchronized (pen) {
							System.out.println(Thread.currentThread()+" :把你的笔给我!");
						}
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		},"Book") ; 
		thread1.start();
		thread2.start();
	}
}

  • 死锁产生的条件:
    1. 多个线程申请所资源
      在这里插入图片描述
      形成的结果:死锁的线程始终处于阻塞态,任务会一直无法执行。
  • 解决方式:
    1. 资源一次性分配(破环请求与保持条件)
    2. 可剥夺资源,在线程满足条件时,释放掉已占有的资源;
    3. 资源有序分配:系统为每类资源赋予一个编号,每个线程按照编号递请求资源,释放则相反。
  • 检测死锁的手段:
    1. jconsole中的检测死锁
    2. jstack

3. volatile

  • 作用:修饰在变量上
    1. 保证内存的可见性
    2. 建立内存屏障,禁止指令重排序
  • 原理:
    1. 如何保证可见性?
      在这里插入图片描述
      缓存一致性协议:读取时,CPU缓存值置为无效,从主存读
      写回主存,发起通知。
    2. 如何禁止指令重排序?
      指令重排序,有as-if-serial的规范,规定了如何重排序(单线程下,前后关联的不能重排序),但是不保证多线程下,指令之间的重排序。
      字节码层面看:
      提供了主存到工作内存,读写操作的8大原子性指令,这些指令,存在happens-before的原则。
      程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作
      监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁;
      volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。(读/写,都是原子性的指令)
      传递性:就是happens-before原则具有传递性,即hb(A,B),hb(B,C),那么hb(A,C).
      CPU层面看
      使用volatile修改的变量操作,CPU指令(汇编)是lock前缀指令(加锁操作)
      变量写回主存时,之前的操作都需要完成;
      加锁属于总线锁/高速缓存锁
      加锁类似于建立了一个屏障:写回主存,之前的都完成,之后的读操作(读和写不能重排序)

4.callable的使用

  • java中,创建线程只有一种方式,必须是new Thread
  • 如何定义线程要执行的任务代码?
    1. 继承Thread,重写run
    2. 实现Runnable,重写run
    3. 实现Callable接口,重写call方法
      提供了一种获取线程执行结果的方式
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //Callable为任务描述,提供了任务执行完毕的返回结果
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println(1);
                return 2;
            }
        };
        //Future/FutureTask,构造时,传入Callable对象,本身是Runnable实现类
        FutureTask task = new FutureTask(callable);

        new Thread(task).start();
        //Future/FutureTask.get():当前线程阻塞等待,直到我们子线程执行完毕(和join方法相类似)并返回结果
        System.out.println(task.get());
        //观察打印3,写在get()前后的不同的结果
        System.out.println(3);
    }
}
  • Runnable和Callable也可以作为任务,在线程池中提交
 new Thread(task).start();
        //Future/FutureTask.get():当前线程阻塞等待,直到我们子线程执行完毕(和join方法相类似)并返回结果
        System.out.println(task.get());
        System.out.println(3);

        //任务类:Runnable,Callable,都可以传入Thread的构造方法
        //其实都是传的Runnable
        //还可以在线程池中提交这两个任务对象
        ExecutorService pool = Executors.newCachedThreadPool();
        //提交任务1
        pool.execute(new Runnable() {
            @Override
            public void run() {

            }
        });
        pool.submit(new Runnable() {
            @Override
            public void run() {
                
            }
        });
        Future<String> future=pool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println(1);
                return "2";
            }
        });
        future.get();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值