/*
多线程,run方法。卖票多线程示例。synchronized,同步锁对象,回顾单例。死锁问题
*/
多线程
进程和线程的区别。
每一个正在执行的程序叫进程,一个进程里至少有一个线程。
多线程存在的意义:让程序同时执行
多线程的创建方式:
第一:就是继承Thread类
1.定义类继承Thread.
2.覆盖run方法。public void run()
3.创建对象。new Demo();
4.调用线程的start()方法。该方法有二个作用。
class Demo extends Thread
{
public void run()
{
for(int x=0;x<60;x++){
System.out.println("Demo run"+x);
}
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
d.start();
for(int x=0;x<60;x++){
System.out.println("main run"+x);
}
}
}
为什么要覆盖run方法?
Thread用于描述线程。该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
也就是说,Thread 类中的run方法,用于存储线程要运行的代码。
Thread t = new Thread();t.start();//要覆盖run方法才有意义。
线程运行的几种状态
被创建,运行,冻结,消亡状态,阻塞状态。
线程都有自己默认的名字。从0开始,getName()获取。
通过构造方法super(String name)可以设置。
Thread.currentThread().getName()===this.getName();
currentThread():获取当前线程对象,静态的,通过
getName():获取线程名字。
设置线程名字:setName()或者构造函数。super();
class Ticket extends Thread
{
private static int tick = 100;//静态可以解决共享数据
public void run()
{
while (true)
{
if (tick>0)
{
System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Tictet t1 = new Tictet();
Tictet t2 = new Tictet();
Tictet t3 = new Tictet();
Tictet t4 = new Tictet();
t1.start();t2.start();
t3.start();t4.start();
}
}
创建线程的第二种方式,1实现一个Runnable接口。2覆写run()方法。
3.通过Thread类创建线程对象。4.把实现接口的类对象作为参数传给Thread();
5.通过Thread类,开启start()。
class Demo implements Runnable
{
public void run()
{
}
}
new Thread(new Demo()).start();
//卖票程序
class Ticket implements Runnable//extends Thread
{
private int tick = 100;//静态可以解决共享数据
public void run()
{
while (true)
{
if (tick>0)
{
System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Tictet t = new Ticket();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
实现方式和继承方式有什么区别?
继承具有局限性,因为java是单继承,继承了Thread类就不能继承别的类。
实现方式的好处在于避免了单继承的局限性,建议使用实现方式。
多线程的安全问题:
卖票当1>0时,此线程等待,其他线程过来,然后再判断1>0,执行完后,然后此线程再减减,会出现负数情况。
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分
还没有执行完,另一个线程参与进来,导致共享数据的错误。
解决办法 :对多条操作共享数据的语句,只能让一个线程执行完,在执行过程中,
其他线程不可以参与执行。
java对于多线程的安全问题,提供了专业的解决方式。同步代码块。
synchronized(对象)
{
需要被同步的代码
}
//这个对象:你想放哪个就放哪个。只要是对象就行。
synchronized(对象)
{
while (true)
{
if (tick>0)
{
System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
同步的二个前提:
1.必须要有两个或者两个以上的线程。
2.必须是多个线程使用同一个锁。
保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源。
把 synchronized 作为修饰符放在函数上,让函数具有同步性。
同步函数用的锁是:方法是被对象调用,前面省略this.方法名();
所以同步函数使用的锁的是:this.
静态同步函数的锁是所在类的Class对象。类名.class
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
class Ticket implements Runnable//extends Thread
{
private int tick = 100;
boolean flag = true;
public void run()
{
if(flag){
while (true)
{
synchronized(this)
//synchronized(Ticket.class)
{
if (tick>0)
{
System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
}
else
{
while(true)
method();
}
}
public synchronized void method()//this
//public static synchronized void method()//Ticket.class
//方法静态,tick也要为静态。
{
if (tick>0)
{
System.out.println(currentThread().getName()+"method:"+tick--);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Tictet t = new Ticket();
new Thread(t).start();
t.flag = false;//变动条件
new Thread(t).start();
}
}
回顾单例设计模式:
饿汉式:
class Single
{
private Single(){}
private static Single s = new Single();
public static Single getInstance()
{
return s;
}
}
//双重判断的安全的懒汉式
class Single
{
private Single(){}
private static Single s = null;
public static Single getInstance()
{
if(s == null)
{
synchronized(Single.class)
{
if (s == null)
{
s = new Single();
}
}
}
return s;
}
}
多线程:死锁问题。
同步中嵌套同步,但是锁不同。
class Ticket implements Runnable//extends Thread
{
private int tick = 100;
boolean flag = true;
Object obj = new Object();
public void run()
{
if(flag){
while (true)
{
synchronized(obj)
{
method();
}
}
}
else
{
while(true)
method();
}
}
public synchronized void method()//this
{
synchronized(obj)
{
if (tick>0)
{
System.out.println(currentThread().getName()+"method:"+tick--);
}
}
}
}
class DeadLockDemo
{
public static void main(String[] args)
{
Tictet t = new Ticket();
new Thread(t).start();
t.flag = false;//变动条件
new Thread(t).start();
}
}
//--------------------------------------------------------
//以下是人造一个死锁
class Test implements Runnable
{
private boolean flag;
Test(boolean flag)
{
this.flag = flag;
}
public void run()
{
if (flag)
{
//如果不出现死锁,可加上while(true).
synchronized(MyLock.locka)
{
System.out.println("if locka");
synchronized(MyLock.lockb)
{
System.out.println("if lockb");
}
}
}
else
{
synchronized(MyLock.lockb)
{
System.out.println("else lockb");
synchronized(MyLock.locka)
{
System.out.println("else locka");
}
}
}
}
}
class MyLock
{
static MyLock locka = new MyLock();//老师视频上用Object
static MyLock lockb = new MyLock();
}
class DeadLockTest
{
public static void main(String[] args)
{
new Thread(new Test(true)).start();
new Thread(new Test(false)).start();
}
}