概念
线程:在进程内多条执行路径
真正的多线程是指多核
这种多线程实际上是模拟的
Java.lang.Thread
通过创建Thread的实例来创建新线程
每个线程都是通过某个thred对象的成员方法run()来进行操作的,run()称为线程体
通过调用Thread类的start()方法来启动一个线程
不要主动调用run()方法,让它内部自己去调
如果当前类已继承别的类,就不能继承Thread了
这时可以通过实现Runnable接口实现多线程
这样可以避免单继承;方便共享资源 同一份资源,多个代理访问
Runnable
上面这个实际上是一种静态代理设计模式
1、真实角色
2、代理角色:持有真实角色的引用
3、二者实现相同的接口
实现过程:
1、创建真实角色
2、创建代理角色+传过去已创建的真实角色
3、start()
这个就是静态代理
方便共享资源的解释
Callable接口
package CallablePractice;
import java.util.concurrent.*;
public class Demo1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService ser = Executors.newFixedThreadPool(1);
Call call = new Call();
Future<Integer> result = ser.submit(call);
int num=result.get();
System.out.println(num);
ser.shutdown();
}
}
class Call implements Callable<Integer> {//注意泛型,因为有返回值,这样可以免去强转
@Override
public Integer call() throws Exception {
return 1000;
}
}
Thread.sleep(time);睡
线程状态
停止线程
destroy和stop均已过时,尽量不要使用,外部干涉终止即可(即用while(flag)等操作即可)
阻塞线程
成员方法join();
阻塞main线程,先等某个线程执行完后再进行main线程
否则就是main执行一下,某个线程执行一下
暂停自己的线程
yield()
:暂停自己的线程 (是静态方法)
写在哪个线程体里面就暂停谁
让出CPU的调度,暂停自己 让别人先执行
sleep()
:休眠,不释放锁
使用的地方:
1、与时间相关,倒计时
2、模拟网络延时
可能导致并发问题
线程基本方法:
currentThread()为静态方法
线程安全、线程同步
synchronized//同步的意思
在方法前面加synchronized
锁定范围不正确、锁定资源不正确都会使线程仍然不安全
范围不能过大,过大会导致访问效率低下
过小会导致访问不完全
同步可以用在懒汉式单例设计模式里面
死锁
过多的同步方法可能导致死锁
比如两份资源a b在两个线程AB里都调用
线程A拿了a的锁,等待b的锁的释放
B线程拿了b的锁,等待a的锁的释放
但是因为在互相等,所以互不释放,因为互不释放,所以一直在等,形成死锁
解决死锁的方案
生产者消费者模式
这里的生产者是生产数据放到缓冲区,消费者是在缓冲区消费数据。要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据
解决方法:让生产者在缓冲区满时休眠,等下次消费者消耗数据时再被唤醒,开始添加数据。
信号灯法
开一个flag
flag为true说明生产者已生产了,让消费者使用
false说明消费者产完了,让生产者使用
wait():等待,释放锁
sleep:不释放锁
noify() notifyAll():唤醒
wait()和notify()要和同步一起使用
Timer类
void schedule(TimeTask task,Date time)安排在指定的时间执行指定的任务
TimerTask实现了Runnable