1.并发:多个程序同时执行。
2.进程:计算机正在运行的程序。线程:程序的具体执行路径。一个进程中至少有一个线程。
3.线程的创建,方式一继承Thread类,重写Thread类的run方法。创建该类的实例,调用start方法,该方法有两个作用,启动线程并且调用run方法。
匿名内部类的实现方式:
public class Demo2 {
public static void main(String[] args) {
new Thread() {
public void run() {
for(int i=0;i<100;i++){
System.out.println("mythread:"+1);
}
}
}.start();
for (int i = 0; i < 100; i++) {
System.err.println("main:" + i);
}
}
}
方式二:自定义类实现Runnable接口里面的run方法,新建Thread类对象,在构造的时候将自定义类的实例对象作为构造参数传递进去。调用Thread类的start方法。
4.Java启动就存在的两个线程,main方法主线程,垃圾回收机制后台线程。
5.。线程的状态,新建,不具备cup的执行权不具备执行资格;可运行状态,具备执行资格不具备执行权;执行状态,具备执行资格和执行权;阻塞状态:不具备具备执行资格不具备执行权。消亡状态,释放执行权执行资格
6.wait() 和 sleep()有什么区别?
wait():释放资源,释放锁。是Object的方法
sleep():释放资源,不释放锁。是Thread的方法
7.死锁案例,嵌套同步代码块。互相持有对方的锁不释放
public static void main(String[] args) {
MyRunTick mt = new MyRunTick();
Thread t1 = new Thread(mt, "一号窗口");
Thread t2 = new Thread(mt, "二号窗口");
Thread t3 = new Thread(mt, "三号窗口");
Thread t4 = new Thread(mt, "四号窗口");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyRunTick implements Runnable {
private int ticket = 100;
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName()
+ "@卖: " + this.ticket + " 号票");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
} else {
System.out.println(Thread.currentThread().getName()
+ "@不好意思去找黄牛吧");
break;
}
}
}
}
}
总结:
同步的前提必须有两个或者两个以上线程, 多个线程使用的是同一个锁.
就是在一个线程执行完卖票时,要保证其他线程进入之前执行完.
线程同步的前提:
必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
线程同步的特点
解决了线程安全问题,(一个共享资源被多个线程同时访问,就可能出现线程安全问题)
即使获取了CPU的时间片,没有对象锁也无法执行
单线程无需同步
线程同步的弊端:
多个线程都需要判断锁较为消耗资源(加了锁之后,一个线程进入该方法后,就持有了锁,在释放锁之前,其他线程即使拥有cpu时间, 没有对象锁也无法执行,只能等到该线程执行完该方法,释放锁)
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
总结:实现和方式和继承方式有什么区别
实现的好处:避免了单继承的局限性定义线程时建议使用实现方式
区别:继承Thread线程代码存放在Thread子类run方法中,实现Runnable线程代码存放在接口子类的run方法中
8.线程之间的通信
线程间通信其实就是多个线程在操作同一个资源,但操作动作不同,wait,notify(),notifyAll()都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。
为什么这些方法定义在Object类中
因为这些方法在操作线程时,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被统一锁上notify唤醒,不可以对不同锁中的线程进行唤醒,就是等待和唤醒必须是同一个锁。而锁由于可以使任意对象,所以可以被任意对象调用的方法定义在Object类中
9.Thread的join方法
当A线程执行到了B线程Join方法时A就会等待,等B线程都执行完A才会执行,Join可以用来临时加入线程执行
10.后台线程:就是隐藏起来一直在默默运行的线程,直到进程结束。
实现:
setDaemon(boolean on)
特点:
当所有的非后台线程结束时,程序也就终止了同时还会杀死进程中的所有后台线程,也就是说,只要有非后台线程还在运行,程序就不会终止,执行main方法的主线程就是一个非后台线程。