线程案例
举个买火车票的案例
package com.wbs.Thread;
public class Tickets implements Runnable {
int tickets=10;//票数
@Override
public void run() {
//5人买票
for (int i = 0; i < 5; i++) {
if(tickets>0){
System.out.println("线程"+Thread.currentThread().getName()+"买票 剩余票数"+(tickets--));
}
}
}
public static void main(String[] args) {
Tickets th=new Tickets();
Thread th1=new Thread(th);
Thread th2=new Thread(th);
Thread th3=new Thread(th);
th1.start();
th2.start();
th3.start();
}
}
每次运行的结果不一样。
分析:
线程有5种状态
新建状态:通过 new 新创建了一个线程对象。
就绪状态:线程对象创建后,调用了该对象的 start() 方法。
变得可运行,等待获取 CPU 的使用权。
运行状态:就绪状态的线程获取了CPU,执行程序代码。
阻塞状态:阻塞状态是线程因为某种原因放弃 CPU 使用权,暂时停止运行。
直到线程进入就绪状态,才有机会转到运行状态。
死亡状态:线程执行完了或者因异常退出了 run() 方法,该线程结束生命周期。
package com.wbs.Thread;
public class Test implements Runnable {
@Override
public void run() {
}
public static void main(String[] args) {
Test test=new Test();
Thread th=new Thread(test);
System.out.println("线程启动前"+th.isAlive());
th.start();
System.out.println("线程 启 动 后"+th.isAlive());
System.out.println("线程 的 名 字"+Thread.currentThread().getName());
System.out.println("线程的 优 先级"+Thread.currentThread().getPriority());//优先级
System.out.println("线程的最大优先级"+Thread.MAX_PRIORITY);//最大优先级
System.out.println("线程的最小优先级"+Thread.MIN_PRIORITY);//最小优先级
System.out.println("线程的默认优先级"+Thread.NORM_PRIORITY);//默认优先级
th.setPriority(2);//设置优先级
System.out.println(th.getPriority());
}
}
Java 线程的优先级用整数表示,取值范围是1~10。
Thread 类有以下三个静态常量:
static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。
setPriority() 和 getPriority() 方法分别用来设置和获取线程的优先级
join()
在当前线程中调用另一个线程的 join() 方法
则当前线程转入阻塞状态
直到另一个进程运行结束
当前线程再由阻塞转为就绪状态。
package com.wbs.Thread;
public class JoinThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
JoinThread th=new JoinThread();
Thread t=new Thread(th);
t.start();
for(int i=0 ;i<5;i++){
if(i==3){
t.join();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(Thread.currentThread().getName()+">>>>>>>>"+i);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
}
System.out.println(Thread.currentThread().getName()+">>>>>>>>"+i);
}
}
}
sleep()
让线程休眠
进入阻塞状态当睡眠结束后
就转为就绪状态
睡眠类:
package com.wbs.Thread;
public class Sleep implements Runnable{
@Override
public void run() {
System.out.println("进入run方法");
try {
Thread.sleep(3000);
System.out.println("线程睡眠结束");
} catch (InterruptedException e) {
System.out.println("线程睡眠被中断");
return;
}
System.out.println("run方法正常结束");
}
}
测试:
th.interrupt();//中断线程
interrupt();//中断线程
yield()
Thread 类中提供了一种礼让方法 使用 yield() 方法表示 暂停当前正在执行的线程对象 把执行机会让给相同或者更高优先级的线程 但是 实际中无法保证 yield() 达到让步的目的 就好像我们在做公交车的时候 总会有声音提示“请给...让座” 但是实际上是什么情况就无法保证了
package com.wbs.Thread;
public class TestYield implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+">>>>>>>>"+i);
}
}
public static void main(String[] args) {
TestYield th=new TestYield();
Thread t= new Thread(th);
t.start();
for (int i = 0; i < 10; i++) {
if(i==5) {
Thread.yield();//当前正在执行的线程礼让一次
//System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
}
System.out.println(Thread.currentThread().getName()+">>>>>"+i);
}
}
}
线程安全还是举买车票的例子吧!
我们在等待的时候会有延迟。可能会有其他线程抢占资源。导致数据出现错误
线程执行原理:
线程执行还没有执行完毕时,被其他线程抢占资源 ,再回到本线程上,再上一次线程执行的基础上对程序继续执行
就好像我们利用迅雷下载东西的时候 下载的东西多了 会排队
有些资源就会插队
等插队的资源下载完了
原来的资源继续下载
这个买票的程序出错了,原因是线程不同步的。
解决方法:
同步代码块:
可以指定对象(同步就是我一段代码执行完毕,我没执行完别人不能动)
使用 synchronized 关键字对代码块进行修饰
对共享资源上锁,锁的是共享资源的对象
package com.wbs.Thread;
public class Tickets2 implements Runnable {
int tickets=10;//票数
@Override
public void run() {
//5人买票
for (int i = 0; i < 5; i++) {
synchronized(this){
if(tickets>0){
System.out.println("线程"+Thread.currentThread().getName()+"买票 剩余票数"+(tickets--));
}
}
}
}
public static void main(String[] args) {
Tickets2 th=new Tickets2();
Thread th1=new Thread(th);
Thread th2=new Thread(th);
Thread th3=new Thread(th);
th1.start();
th2.start();
th3.start();
}
}
同步方法:
(监视的对象只能是this)
在方法上加synchronized关键字
在方法上加锁,锁的依旧是对象
package com.wbs.Thread;
public class Tickets3 implements Runnable {
int tickets=10;//票数
@Override
public void run() {
//5人买票
for (int i = 0; i < 5; i++) {
show();
}
}
public synchronized void show(){
if(tickets>0){
System.out.println("线程"+Thread.currentThread().getName()+"买票 剩余票数"+(tickets--));
}
}
public static void main(String[] args) {
Tickets3 th=new Tickets3();
Thread th1=new Thread(th);
Thread th2=new Thread(th);
Thread th3=new Thread(th);
th1.start();
th2.start();
th3.start();
}
}
线程同步总结:
同步监视器:
synchronized(obj){}中obj成为同步监视器
同步代码块中同步监视器可以是任何对象
但是推荐使用共享资源作为同步监视器
同步方法中无需指定同步监视器
因为同步方法的监视器是this,也就是说是该对象本身
同步监视器的执行过程:
第一个线程访问,锁定同步监视器,执行其代码
第二个线程访问,发现同步监视器被锁定了,无法访问
第一个线程访问完毕,解除同步监视器
第二个线程访问,发现同步监视器未锁,锁定并访问
同步的缺点:
死锁:
同步可以保证资源共享操作的正确性
但是过多的同步也会产生死锁
当双方都在等待对方资源的时候
程序就进入了阻塞状态,无法执行
上一篇: 开多线程进行分发
下一篇: Python3使用Cookie-模拟登陆