Java创建多线程的两种基本方法:
方法1.继承Thread类
(1)定义子类,继承Thread类,重写该类的run()方法作为线程执行体;
(2)创建该子类的实例作为线程对象;
(3)调用线程对象的start()方法来启动线程;
我们以模拟火车售票系统为例:
public class SellTicket {
public static void main(String[] args) {
for(int i=1; i<4; i++){
TicketWindow tw = new TicketWindow();
tw.setName("TicketWindow-" + i);
tw.start();
}
}
}
class TicketWindow extends Thread{
private int tickets = 100;//车票总量
@Override
public void run(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");
tickets--;
System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");
break;
}
}
}
}
方法2.实现Runnable接口
(1)定义类实现Runnable接口,重写run()方法;
(2)创建该实现类的实例,以该实例作为Thread的target来创建Thread对象;
(3)调用该Thread对象的start()方法来启动该线程;
还是以模拟火车售票窗口为例:
public class SellTicket {
public static void main(String[] args) {
TicketWindow tw = new TicketWindow();
for(int i=1; i<4; i++){
Thread t = new Thread(tw,"TickWindow-" + i);
t.start();
}
}
}
class TicketWindow implements Runnable{
private int tickets = 100;//车票总量
@Override
public void run(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");
tickets--;
System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");
break;
}
}
}
}
注意:
继承Thread类与实现Runnable接口的区别及优缺点对比:
继承Thread类 | 实现Runnable接口 | |
能否继承其他类 | 不能 | 能 |
如何访问当前线程 | this即为当前线程 | Thread.currentThread() |
是否共享同一target | 否 | 是,适合多个相同线程处理同一份资源的情况 |
因此,一般推荐采用实现Runnable接口/Callable接口的方式创建多线程;
虽然上面实现Runnable接口的火车售票系统共享了车票总数,但是没有控制同一时刻只能有一个线程进行卖票操作,因此需要同步关键字 synchronized 进行控制,
线程同步分为同步块和同步方法:
1.同步块
同步块的语法格式为: