1,线程概念:
class Demo11 extends Thread{
public void run()
{
for(int x=0;x<70;x++)
System.out.println("Demo---run"+x);
}
}
class Demo
{
public static void main(String[] args)
{
Demo11 d = new Demo11();//创建了一个对象就相当于创建了一个线程。
d.start();//开启线程并且调用了run方法。
d.run();//仅仅是对象调用run方法,并没有开启线程。
for (int x=0;x<90;x++)
System.out.println("Hello World!"+x);
}
}
结论:
每次运行结果都不一样。
因为多个线程在抢夺cpu执行权,谁抢到,cpu就执行谁。至于执行多久,cpu说了算。
明确一点:其实在某一个时刻,只能有一个程序在运行(多核除外),但是cpu在做着快速切换,达到看起来是同时执行的效果。
3,run和start的特点:
1,为什么要继承Tread,覆盖run方法?
run方法用于存储线程要运行的代码,让线程运行。
2,d.start();//开启线程并且调用了run方法。
d.run();//仅仅是对象调用run方法,并没有开启线程。
3,线程运行的状态:
被创建:创建一个Thread或者其子类对象。
运行:调用start()方法。既有执行资格又有执行权。
冻结:sleep(time),time结束后,进程恢复;wait(),notify()来唤醒线程。放弃执行资格。被唤醒或者时间到了以后先回到阻塞状态。
消亡:sop();run方法结束。
临时状态(阻塞):具备执行资格,但是没有cpu执行权
4,获取线程对象、名称:
线程都有自己默认的名称,Thread-编号 该编号从0开始。
static Thread currentThread():获取当前线程对象。
getName():获取线程名称
setName():修改线程名称,也可以通过构造函数传递参数来修改。
eg:
class Demo11 extends Thread
{
//private String name;
Demo11(String name)
{
//this.name=name;
super(name);
}
public void run()
{
for(int x=0;x<70;x++)
System.out.println((Thread.currentThread()==this)+"---"+this.getName()+"---run"+x);
}
}
class Demo
{
public static void main(String[] args)
{
Demo11 d1 = new Demo11("one--");
Demo11 d2 = new Demo11("two++");
d1.setName("hahahahahhahahha");
d1.start();
d2.start();
for (int x=0;x<90;x++)
System.out.println("Hello World!"+x);
}
}
eg2:
class Ticket extends Thread
{
// private int tick = 100;
private static int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
System.out.println(currentThread().getName()+"tick: "+tick--);
}
}
}
class TickedDemo
{
public static void main(String[] args)
{
Ticket t1 = new Ticket();//一个线程有100张票,一共卖出400张票。
// Ticket t2 = new Ticket();
// Ticket t3 = new Ticket();
// Ticket t4 = new Ticket();
t1.start();//java.lang.IllegalThreadStateException;无效线程状态异常。
t1.start();
t1.start();
t1.start();//一个窗口在卖票。。
// t2.start();
// t3.start();
// t4.start();
//System.out.println("Hello World!");
}
}
5,创建线程:实现Runnable接口
class Ticket2 implements Runnable
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
System.out.println(Thread.currentThread().getName()+"tick: "+tick--);
}
}
}
class TickedDemo2
{
public static void main(String[] args)
{
Ticket2 t = new Ticket2();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
6,多线程的安全问题:
发现打印出了0,-1,-2等错票问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对语句执行了一部分,还没有参与进来,另一个线程参与进来,导致共享数据错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行的过程中,其他线程不能参与运算。java中解决多线程安全问题的方法是:同步代码块儿:
synchronized(对象)
{需要被同步的代码}
eg:
class Ticket2 implements Runnable
{
private int tick = 10000;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"tick: "+tick--);
}
}
}
}
}
class TickedDemo2
{
public static void main(String[] args)
{
Ticket2 t = new Ticket2();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
7,同步代码块:
如何找出安全问题?
1,明确哪些代码是多线程运行的代码。
2,明确共享数据。
3,明确多线程中哪些共享数据被多条语句操作。
eg:
/**
需求:银行有一个金库,有两个储户分别存300元,每次存100,存3次
*/
class Bank
{
private int Sum=0;
Object obj = new Object();
public synchronized void add(int n)//这里可以声明
{
//synchronized(obj)
// {
Sum+=n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("SUM="+Sum);
// }
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
public void run()//run方法中不可以抛出异常,只能处理。
{
for (int x=0;x<3;x++)
{
b.add(100);
}
}
}
class BankDemo
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
9,同步函数的锁是this
class Ticket2 implements Runnable
{
private int tick = 500;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(obj)//代码块的锁是obj对象
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"code: "+tick--);
}
}
}
}
else
{
while(true)
show();
}
}
public synchronized void show()//同步函数的锁是this
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"show***********: "+tick--);//33
}
}
}
class ThisDemo
{
public static void main(String[] args)
{
Ticket2 t = new Ticket2();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();//执行完这里,t1具备了资格,但是还没获得执行权,主线程接着把11、22执行完。这时候t2获得执行资格,并且获得执行权,这时只有33执行。因此下边让主线程停一会儿
//try{Thread.sleep(10);}catch(Exception e){}//主线程sleep一会儿,线程0执行,主线程醒了,执行线程1
t.flag = false;//11
t2.start();//22
}
}
10,静态同步函数的锁是Class对象
class Ticket2 implements Runnable
{
private static int tick = 500;
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(Ticket2.class)//
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"code: "+tick--);
}
}
}
}
else
{
while(true)
show();
}
}
public static synchronized void show()//静态同步函数的锁是该对象所在的字节码文件对象:类名.class,该对象的类型是Class
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"show***********: "+tick--);//33
}
}
}
class StaticDemo
{
public static void main(String[] args)
{
Ticket2 t = new Ticket2();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();//执行完这里,t1具备了资格,但是还没获得执行权,主线程接着把11、22执行完。这时候t2获得执行资格,并且获得执行权,这时只有33执行。因此下边让主线程停一会儿
try{Thread.sleep(10);}catch(Exception e){}//主线程sleep一会儿,线程0执行,主线程醒了,执行线程1
t.flag = false;//11
t2.start();//22
}
}
11,单例设计模式:
俄汉式:class Single{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
懒汉式:
class Singgle
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if (s==null)
{
s=new Single();
}
}
}
return s;
}
}
2,俄汉式:多线程时不会安全问题懒汉式:用于延迟加载,多线程时会出现安全隐患,建立了多个对象,不符合单例设计模式的原则。
如何解决懒汉式安全问题:可以加同步和同步函数可以解决,但是效率较低,可以用双重判断的形式解决低效问题,同步所属的对象时该类所属的字节码文字对象。
12,死锁:
class LockDemo implements Runnable
{
private boolean flag = true;
LockDemo(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
{
while(true)
{
synchronized(MyLock.lockb)
{
System.out.println("if lockb");
synchronized(MyLock.locka)
{
System.out.println("if locka");
}
}
}
}
}
}
class MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
}
class DeadLockDemo
{
public static void main(String[] args)
{
Thread t1 = new Thread(new LockDemo(true));
Thread t2 = new Thread(new LockDemo(false));
t1.start();
t2.start();
}
}