线程/多线程

在这里插入图片描述
1、Thread.sleep(long millis),一定是当前线程调用此方法,当前线程进入阻塞,但不释放对象锁,millis后线程自动苏醒进入可运行状态。作用:给其它线程执行机会的最佳方式。

2、Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的cpu时间片,由运行状态变会可运行状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。

3、t.join()/t.join(long millis),当前线程里调用其它线程1的join方法,当前线程阻塞,但不释放对象锁,直到线程1执行完毕或者millis时间到,当前线程进入可运行状态。
4、obj.wait(),当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒。
5、obj.notify()唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。

join() 和 join(long millis, int nanos) 最后都调用了 join(long millis)。

join(long millis, int nanos)和join(long millis)方法 都是synchronized。

join() 调用了join(0),从源码可以看到join(0)不断检查当前线程是否处于Active状态。

join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException
异常);不同的是,join() 内部调用了wait(),会出让锁,而 sleep() 会一直保持锁。

启动线程的三种方式
①:继成java.lang.Thread, 重写run()方法
②:实现java.lang.Runnable接口,重写run()方法,然后使用Thread类来包装

// 将Runnable实现类作为Thread的构造参数传递到Thread类中,然后启动Thread类
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();     

③:实现Callable接口,重写call()方法,然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread

// 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();

生产者消费者问题:

等等写----


BlockingQueue阻塞队列

ArrayBlockingQueue:
一个由数组支持的有界阻塞队列,规定大小的BlockingQueue,其构造函数必须带一个int参数来指明大小,其所含的对象是以先入先出的顺序排序的
LinkedBlockingQueue:基于链表的阻塞队列,大小不定的BlockingQueue,可以指定长度,不指定默认为Interger.MAX_VALUE,也是先入先出的顺序排序的,主要用到put和take,put方法在队列满的时候会阻塞知道有队列成员被消费,take方法在队列空的时候会阻塞,知道有新的队列成员被放入
PriorityBlockingQueue:带有优先级的BlockingQueue DelayQueue:
一定时间之后才可以take的BlockingQueue
SynchronousQueue:直接传递的BlockingQueue,用于执行Producer角色到Consumer角色的直接传递。

ConcurrentLinkedQueue: 元素个数没有最大限制的线程安全队列,该类不是BlockingQueue的子类,
内部数据结构是分开的,线程之间互不影响,所以也就无需执行互斥处理。根据线程情况的不同,有时程序的性能也会有所提高。

线程池七大参数

(1)corePoolSize:线程池中常驻核心线程数

(2)maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1

(3)keepAliveTime:多余的空闲线程存活时间。当前线程池数量超过corePoolSize时,当空闲时间到达keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。

(4)unit:keepAliveTime的时间单位

(5)workQueue:任务队列,被提交但尚未执行的任务

(6)threadFactory:表示生成线程池中的工作线程的线程工厂,用于创建线程,一般为默认线程工厂即可

(7)handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝来请求的Runnable的策略

在这里插入图片描述
创建线程池的几种方式:

//创建固定线程数量的线程池
 ExecutorService threadPool = Executors.newFixedThreadPool(5);
 //创建只有一个线程的线程池,所有提交的线程是顺序执行的
ExecutorService executorService = Executors.newSingleThreadExecutor();
//创建一个可缓存的线程池
ExecutorService executorService1 = Executors.newCachedThreadPool();
//创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类
ExecutorService executorService2 = Executors.newSingleThreadScheduledExecutor()

volatile
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  • 禁止进行指令重排序。

线程的三种特性:
原子性:对基本数据类型的变量的【读取】和【赋值】操作是原子性操作,即这些操作是不可被中断的,一次性必须执行完成的,要么执行,要么不执行。
如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。
可见性:volatile关键字增加了实例变量在多个线程之间的可见性
有序性:可以通过volatile关键字来保证一定的“有序性”。另外可以通过synchronized和Lock来保证有序性,很显然,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值