并发:两个或多个事件(线程)在同一时间段内发生(一个Cpu交替执行)
并行:两个或多个事件(线程)在同一时刻发生
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
进入到内存的程序就是进程
线程:能独立运行的基本单位,也是独立调度和分派的基本单位, 不具备独立的内存空间
主线程:执行main方法的线程
main方法执行过程:JVM执行main方法,首先将main方法放入栈内存中,开辟一条main通向CPU的路
径,这个路径就叫做main(主)线程。
1、创建一个Thread的子类
2、重写Thread的run() 方法,run中写的是新线程执行的任务
3、创建一个Thread的子类对象
4、main中调用该对象的start方法
1、创建一个实现类实现Runnable接口,实现类中实现run()方法,设置线程任务
2、创建一个实现类对象
3、创建一个thread对象,构造方法中传递Runnable实现类对象名称
4、利用Thread对象调用start()方法,开启新线程执行run()方法
(线程多次启动是违法的,线程结束执行结束后,不能再重新启动)
1、Java不允许多继承,使用Runnable实现后,还可以继承其它类
2、方便资源共享(共享一个实例对象),将设置线程任务和开启新线程进行了分离(解耦),增强了程序的可扩展性,
public class SnapUpThread implements Runnable {
private int ticket = 100;
static int i = 0;
String name = "用户";
@Override
public void run() { //设置线程任务
i++;
int nameNumber = i;
while(true){
if (ticket <= 0) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + nameNumber + "抢到票:" + ticket--);
}
}
}
public static void main(String[] args) {
SnapUpThread runnable = new SnapUpThread();
new Thread(runnable).start(); //开启新线程
new Thread(runnable).start(); //开启新线程
}
结果:
当JVM执行main方法时,开辟了一条从main方法通向CPU的路径(线程),当执行到Thread th = new newThread();时,由再开辟一条从th通向CPU的路径,执行到start()方法时便开始执行th线程的run方法。
对于CPU而言,便有了选择权,随机选择线程执行,这就有了程序的随机打印结果。同样也可以认为,两个线程同时抢夺CPU的执行权(执行时间)。
在卖票时(操作共享数据),即使失去cpu控制权,也不允许其它线程来操作共享数据。
当一个线程1抢到cpu使用权后,执行到synchronized语句时,获得了唯一的锁对象,因此就算失去cpu使用权,别的线程因为没有得到锁对象,会一直在synchronized语句阻塞,直到线程1释放出锁对象。
synchronized(锁对象){
//操作共享数据的语句
}
注意:
把操作共享数据的语句封装成一个方法,方法修饰符后增加synchronized
(同步方法的锁对象其实就是创建的Runnable实现类对象,所以在第一个方法中也可以使用this作为锁对象传入)
public synchronized int payTicket(){
if (ticket <= 0) {
return 0;
}
System.out.println(name + nameNumber + "抢到票:" + ticket);
ticket--;
return 1;
}
int a = 1;
while(a == 1){
a = payTicket();
}
1、创建ReentrantLock rt = new ReentrantLock();
2、在操作共享数据的语句前加锁:rt.lock();
3、在操作完共享数据的语句后放掉锁:rt.unlock();