多线程的实现步骤 :从开始创建的时候到线程的执行,最终到线程的终止
1)新建线程:没有执行资格,没有执行权
2)线程就绪:有执行资格,但没有执行权
(这里可能也会发生线程阻塞状态:线程睡眠或者等待)
3)线程执行:有执行资格并且有执行权
4)线程死亡:线程执行完毕,会被垃圾回收线程中的垃圾回收器及时的从内存中释放掉
当我们运行多线程模仿现实窗口售票应该怎么做?
例如:
使用实现Runnable方式
package com.westos.Runnable;
public class MyRunnable implements Runnable{
/**
* 同步锁的对象可以是任意的java类对象
* 例如我们在下方定义一个Dome类,并在此创建Dome类对象
* 然后将同步锁的对象换成Dome类对象,依旧可以模拟现实窗口售票
*/
private Dome d=new Dome();
//定义一个私有公用的票数变量
private static int tickets=100;
定义同一把锁对象
//private Object obj=new Object();
@Override
public void run() {
while(true) {
/**
* 为了多个线程可以享用到共享资源我们必须的设置同一把锁,不然依旧会出现好几个窗口在出售同一张票的情况
* 这里的synchronized()方法就好比是一扇门,当其中的一个线程进来后就会关闭这扇门,然后去享受资源
* 等它享受完后,下一个线程会继承抢着进来享受资源,每一线程进来后
* 共享代码块就会发挥它的作用,这样就不会出现同票和负票的现象了
*/
synchronized (d) {
if(tickets>0) {
//模范现实售票延迟的效果,给线程加入睡眠的功能(睡眠100毫秒)
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//因为上面是运用了实现Runnable接口的方法,不能直接调用getName方法,当你使用继承Thread类方式时,就可以使用了
//必须通过Thread类中的返回正在运行的线程的方法再用它去调用getName方法
System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
}
}
}
}
class Dome{
}
}
创建一个测试类
package com.westos.Runnable;
/**
* 当我们模拟现实售票的情况时,会出现窗口出售同一张票的情况以及出现负票的情况
* (例如窗口1正在出售第0张票或者窗口1正在出售第-1张票的情况)
*解决方法:
* 将我们的共享数据用同步代码块包起来
* 格式synchronized(锁对象){
* 多条语句对共享数据的使用代码
* }
*
*/
public class RunnableDome {
public static void main(String[] args) {
//创建资源类对象
MyRunnable my=new MyRunnable();
//创建Thread类对象
Thread t1=new Thread(my,"窗口1");
Thread t2=new Thread(my,"窗口2");
Thread t3=new Thread(my,"窗口3");
//执行线程
t1.start();
t2.start();
t3.start();
}
}
当我们把同步锁放在方法中以及放在方法上时,依旧可以去模拟现实中窗口售票
切记:
当方法是静态时,记住要锁对象是该类名.class
例如:
package com.westos.Runnable;
public class SellTicket implements Runnable{
//创建Dome类对象
Dome d=new Dome();
//定义一个通用的票数
private static int ticket=100;
//定义一个变量
private int x=0;
@Override
public void run() {
//循环
while(true) {
if(x%2==0) {
synchronized (SellTicket.class) {//当方法时静态时:锁对象:类名.class; 当方法不是静态时,锁对象是this
if(ticket>0) {
//让共享资源睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"张票");
}
}
}
else {
sellTicket();
}
x++;
}
}
//我们可以将同步锁写在方法中,然后在run方法中调用即可
/*private void sellTicket() {
synchronized (d) {
if(ticket>0) {
//让共享资源睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"张票");
}
}
}*/
//或者我们可以直接把同步锁写在方法上去调用
//当该方法时静态的时候,该类中的锁对象是类名.class
private synchronized static void sellTicket() {
if(ticket>0) {
//让共享资源睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"张票");
}
}
class Dome{
}
}
package com.westos.Runnable;
public class SellTicketDome {
public static void main(String[] args) {
//创建资源类对象
SellTicket st=new SellTicket();
//创建三个Thread类对象
Thread t1=new Thread(st,"窗口1");
Thread t2=new Thread(st,"窗口2");
Thread t3=new Thread(st,"窗口3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
运行结果:
窗口2正在出售第7张票
窗口3正在出售第6张票
窗口1正在出售第5张票
窗口1正在出售第4张票
窗口3正在出售第3张票
窗口3正在出售第2张票
窗口3正在出售第1张票
我们目前学习了线程安全的类有三个:
StringBuffer缓冲区、Vector集合、Hashtable集合
接下来让我们学习一种将线程不安全的类转换成线程安全类的方法
例如:
package com.westos.synchronizedList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
public class synchronizedListDome {
public static void main(String[] args) {
//目前我们学习过的线程安全的类有:
StringBuffer sb=new StringBuffer();
Vector v=new Vector();
Hashtable ht=new Hashtable();
/**
* 但是当我们运用一些集合的时候还是习惯用ArrayList集合
* 所以我们应该怎么将一些线程不安全的类转变成线程安全 的类呢
* 接下来就需要运用到collections工具类的synchronizedList方法了
*/
//创建ArrayList集合对象,将类型定为String类型
ArrayList<String> list=new ArrayList<String>();
//调用方法://public static <T> List<T> synchronizedList(List<T> list)
//返回是List集合,返回的集合就是线程安全的类了
List<String> array = Collections.synchronizedList(list);
}
}