线程的生命周期
JDK中用Thread.State类定义了线程的几种状态 想要事项多线程,必须在主线程中创建新的线程对象。java语言使用Thread类及其子类的对象来表示线程,在它的一个完整生命周期中通常要经历以下五种状态:
- 新建:当一个Thread类或其子类的对象呗声明并创建时,新生的线程对象处于新建状态。
- 就绪:处于新建状态的线程被start()后,将进入线程队列等待cpu时间片,此时它已具备了运行的条件,只是没有分配到cpu资源。
- 运行:当就绪的线程被调度并获得cpu资源时,便进入运行状态,run()方法定义了线程的操作和功能。
- 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出cpu并临时终止自己的执行,进入阻塞状态。
- 死亡:线程完成了它的全部工作或者线程被提前强制性终止或出现异常导致结束。
线程的同步
问题的提出:
- 多个线程执行的不确定性引起执行结果的不稳定
- 多个线程对账本的共享,会造成操作的不完整性,会破坏数据。
同步代码块方式:
/*
* 1 问题: 在卖票过程中出现了重票,错票--->线程安全问题
* 2 问题出现的原因:某个线程操作车票过程中,尚未操作完成是,其他线程也对车票进行操作。
* 3 如和解决:当一个线程在操作共享数据时,其他线程不能参与进来,直到当前线程操作完成时才可以操作。
* 这种
* 方式一 同步代码块
* synchronized(同步监视器){
* //需要被同步的代码
* }
* 同步监视器:俗称锁。任何一个类的对象都可以充当锁
* 锁的要求:要求多个线程必须共用同一把锁。
*
* 说明:1 操作共享数据的代码,即为需要被同步的代码
* 2 共享数据:多个线程共同操作的变量
* 3 在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。
*
* 同步的好处:解决了线程的安全问题
* 同步局限性:操作同步代码时只能有一个线程参与,其他线程等待,相当于是一个单线程过程,效率低。
* */
class Window1 implements Runnable {
private int ticket = 100;
Object object = new Object();
@Override
public void run() {
while (true) {
synchronized(object){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class WindowTest1 {
public static void main(String[] args) {
Window1 window1 = new Window1();
Thread t1 = new Thread(window1);
Thread t2 = new Thread(window1);
Thread t3 = new Thread(window1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window2 extends Thread {
private static int ticket = 100;
private static Object object = new Object();
@Override
public void run() {
while (true) {
synchronized(object){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class WindowsTest2 {
public static void main(String[] args) {
Window2 t1= new Window2();
Window2 t2= new Window2();
Window2 t3= new Window2();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
同步方法方式:
/*
* 同步方法:如果操作共享数据的代码完整的声明在一个方法中,
* 我们可以将该方法声明为同步的。
*
* 同步方法总结:
* 1 关于同步方法任然涉及到同步监视器,只是不需要我们现实的声明。
* 2 非静态的同步方法,同步监视器是this
* 静态的同步方法,同步监视器是:当前类本身
*
* */
class Window3 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
public synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest3 {
public static void main(String[] args) {
Window3 window1 = new Window3();
Thread t1 = new Thread(window1);
Thread t2 = new Thread(window1);
Thread t3 = new Thread(window1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window4 extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
show();
}
}
public static synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest4 {
public static void main(String[] args) {
Window4 t1= new Window4();
Window4 t2= new Window4();
Window4 t3= new Window4();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}