Java中线程Thread
线程
概念
线程(英语:thread):是操作系统能够进行独立调度和分派的基本单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以有多个线程并发执行。一个进程可以有一个主线程,在主线程中的线程称为子线程。线程中的资源互相不共享即各自拷贝一份资源。
栈帧:线程中的方法执行结束后从线程栈中弹出的方法称为栈帧。
适用场景
当进程中产生CPU资源浪费的情况下,用多线程做为解决方案更合适。
使用方法
——————此处用一个多线程抢票的例子来解释——————
新建ThreadDemo类继承Thread,重写run()方法
public class ThreadDemo extends Thread {
private String name;//线程名字
private int sellCount=0;//当前线程销售票数
private Flag flag;//记录引用Flag
ThreadDemo(String name,Flag flag){
this.name=name;
this.flag=flag;
}
//在线程start之后会自动执行run方法
@Override
public void run() {
while(flag.SellTickets(flag))
{
try{sleep(10);}//sleep使线程暂时阻塞10ms
catch(InterruptedException e){
e.printStackTrace();
}
sellCount++;
}
System.out.println(toString());
}
@Override
public String toString() {
return "ThreadDemo{" +
"name='" + name + '\'' +
", sellCount=" + sellCount +
'}';
}
}
随后新建Main类,这是我们的主线程,此处我们建立三个线程进行抢票测试
public class Main {
public static void main(String[] args) {
Flag flag=new Flag();
ThreadDemo threadDemo1=new ThreadDemo("柜台1",flag);
ThreadDemo threadDemo2=new ThreadDemo("柜台2",flag);
ThreadDemo threadDemo3=new ThreadDemo("柜台3",flag);
threadDemo1.start();
threadDemo2.start();
threadDemo3.start();
}
}
最后我们建立Flag类,此类是线程间共享的资源所以我们需要对公共资源进行上锁
public class Flag {
public int flag=1;//是否还有余票的判断
public static int tickets=100;//总票数
public synchronized boolean SellTickets(Flag flag){
if(tickets==0)
{
flag.flag=0;
return false;
}
tickets--;
System.out.println(tickets);
return true;
}
}
在上面的SellTickets方法上我们加了synchronized,对tickets的读/写操作都在这个方法内,这样就避免了线程间访问公共资源的冲突问题。
运行结果:
ThreadDemo{name=‘柜台2’, sellCount=34}
ThreadDemo{name=‘柜台1’, sellCount=33}
ThreadDemo{name=‘柜台3’, sellCount=33}
<
我们可以得到最后每个柜台输出的总票数没有超过tickets的数量
join和sleep的区别
join:
看以下例子
threadDemo1.start();
try {
threadDemo1.join(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
该代码可以让后面的代码等threadDemo1执行完毕后再执行,该方法通常用在主线程需要线程执行结果时。
sleep:
顾名思义,即是将线程阻塞起参数T时间,此时除该线程外,其他未阻塞的线程将会继续执行。
锁synchronized
多个线程共同访问内存中同一区域进行访问会产生并发问题和脏数据,
所以需要进行访问控制和数据同步时需要对资源进行加锁,在多线程并发时对共享访问资源加锁才能阻塞线程。
锁在锁方法时只会锁方法中的变量;
类锁和对象锁不能互相锁定;
编程时应将对共享资源的读写都放在加锁的方法里;
可以通过引用的方法来进行线程间的通信和资源控制;
类锁
同一类中对一个非静态的方法加锁其他的非静态方法会同时一起加锁,
静态的锁是类锁也是互相锁定即同时加锁。
对象锁
非静态的方法锁。