一、首先说一下怎么创建多线程的方式
1、创建一个类 继承 Thread 类,重写 run() 方法。
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("创建线程");
}
}
2、创建一个类 实现 Runnable 接口,实现 run() 方法。
public class MyThread implements Runnable{
@Override
public void run() {
System.out.println("创建线程");
}
}
3、同时开启多个线程,并调用该方法。
创建新的线程对象,调用该线程的start()方法,如果调用run()方法,线程的名称都是 main
(1)当使用继承时:
class Test {
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
(2)当使用Runnable时:
在创建实现Runnable接口的对象时,只能创建一个,然后new Thread对象调用start方法启动线程。结果跟之前一样,就不贴出来了。
二、经过基本的了解,下面开始售票的案例:
需求:100张票,三个窗口同时出售,不能出现重票情况。
public class MyThread implements Runnable{
private static int ticket = 100;
@Override
public void run() {
while (true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"-------"+ticket);
ticket--;
}else{
break;
}
}
}
}
class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
输出的结果是:
在这里出现了重复卖出 第100 号票,所以出现了线程安全问题。
解决线程安全问题(利用线程同步的机制)
(1)使用同步代码块
private Object obj = new Object();//这个是 锁,任意对象,但是 对象必须唯一
synchronized (obj){
// 这一块是需要操作的共享数据
}
在继承Thread的对象里需要将 obj 静态化,因为调用new Thread().start()方法时,是创建新的对象,不符合锁的要求。所以需要使用 静态的:
private static Object obj = new Object();
(2)使用同步方法:方法的内部操作共享数据,在方法的权限修饰词后面加一个 synchronized 关键字就行了
实现接口的方式:
public class MyThread implements Runnable{
private static int ticket = 100;
@Override
public void run() {
while (ticket>0){
show();
}
}
private synchronized void show(){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"+++++++++"+ticket);
ticket--;
}
}
}
class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
继承的方式:需要在 synchronized 前面加一个 static 关键字
private static synchronized void show(){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"+++++++++"+ticket);
ticket--;
}
}