day11多线程:
- [ ] 进程:当前正在运行的程序,一个应用程序在内存中的执行区域。
[ ] 线程:进程中的一个执行控制单元,进行路径
一个进程可以有单个到多个线程。
[ ] 单线程:安全性高,效率低
- [ ] 多线程:。。。低,。。高。
多线程的实现:
Thread类:
实现Runnable接口:
构造方法:
new Thread();
new Thread(Runnable r);可以传入实现了该接口的类。
创建新线程的方法:(继承)
1, 定义一个类 继承 Thread
2, 重写 run() 方法
3, 把线程要做的事情(代码)写在该方法里
4, 在主方法里创建 Thread 的子类对象
5, 调用 start() 启动线程
注意:
不可以调用 run()
并没有开启多条线程
class MyThread extends Thread{
void run(){
//需要执行的代码。
}
}
Test{
main(){
MyThread mt = new MyThread();
mt.start;
}
}
Thread类一般方法:
String getName();获取线程名。
void setName(String s);修改线程名。
创建新线程的方法2:(实现)
1>声明一个类实现Runnable接口
2>重写该接口的run()方法
3>在主方法中创建一个或多个实例
4>创建新的线程对象,将实例作为参数传入线程的构造方法(这是为了线程对象可以使用Thread的静态方法)。
5>调用线程的start()
注意:
Thread.currentThread();是Thread类的静态方法,获取当前线程对象(是一个Thread对象)。获取该对象后,可以继续调用Thread的方法。
static void sleep(long millis)当前线程休眠。
在run()方法中,可以定义一个用于计数器的局部变量。当不同的线程执行run方法时,可以分别统计不同线程执行的计数器。并在run方法内打印输出,各个线程都会分别执行对应的计数器打印输出。
多个线程并发访问同一个数据时,会出现不安全的问题。
synchronizes同步
可以修饰代码块和方法,被修饰的代码一旦被某个线程访问,直接锁上,其他线程无法访问。
同步代码块
格式:
synchronizes(锁对象){
}
注意事项:
- [x] 锁对象需要被所有线程共享。锁对象是在类中创建一个共享的对象即可。Object o = new Object();将o作为锁对象传入同步代码块。(这种方式只针对于实现Runnable接口的方法,不能创建多个线程的对象,)
- [x] 同步代码块不要加在了循环体的外面,否则只有一个线程可以进入循环。
- [x] 锁对象要保证是同一个对象,不能是多个。
- [x] 如果是用继承Thread的方式实现多线程共享数据,那么共享数据必须声明是静态的,同步锁也需要设置是静态的,唯一的。因为在主线程中会产生多个该实现类来实现多线程,必须共享该类的静态成员。
同步方法:
使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法全部锁住,其他线程则无法访问
注意事项:
使用关键字synchronized修饰的方法,一旦被一个线程访问,其他线程不能访问。
将同步代码块中的代码抽取为方法,然后将方法的调用放在同步代码块中
或者将方法的声明中定义为synchronizes的,即同步方法
同步方法的锁对象是默认的,非静态同步方法是this.调用方法当前对象的引用。静态方法同步对象是.class对象,即当前类的字节码文件。
死锁
基本上都是由于 同步代码块的嵌套使用 导致的
死锁: (有可能在面试的时候,让你手写!!!)
大家以后在实际开发,一定要避免出现 这种嵌套的使用
class MyRun implements Runnable {
int num = 0;
//准备两把锁
String s1 = "老王";
String s2 = "小王";
@Override
public void run() {
while(true){
if(num % 2 == 0){
//线程1进来了
//同步代码块的嵌套
synchronized (s1) {//线程2进来了
//线程2 拿到了 s1 进来了...
System.out.println(Thread.currentThread().getName()+"拿到了"+s1+num);
synchronized (s2) {//线程1进来了
System.out.println(Thread.currentThread().getName()+"拿到了"+s2+num);
}//s2的右大括号
}//s1的右大括号
}else{
//同步代码块的嵌套
synchronized (s2) {//线程 1进来了... 意味着拿到了 小王...
System.out.println(Thread.currentThread().getName()+"拿到了"+s2+num);
//线程1 失去了cpu的执行权,处于等待的状态...
synchronized (s1) {
System.out.println(Thread.currentThread().getName()+"拿到了"+s1+num);
}
}
}
//不管走if还是else 都让num++
num++; //1
}
}
}