Day11
/*
进程:是一个正在被执行中的程序。
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立完成控制单元。
线程在控制着进程的执行。
一个进程中至少有一个线程。
创建线程的第一种方式, 继承Thread类
步骤:
1.定义类继承Thread类
2.复写Thread类中的run方法,(目的是将自定义代码存储在run方法中,让线程运行。)
3.实例化定义的类,调用start方法,
start方法有两个作用,1)启动线程 2)调用run方法
为什么覆盖run方法呢
Thread类用于描述线程。
该类定义了一个功能,用于存储线程要运行而定代码,该存储功能就是run方法。
也就是说Thread类中的run方法,用于存储线程运行的代码。
*/
class D11Demo extends Thread
{
public void run()
{
for (int i=0;i<100;i++ )
{
System.out.println("---demo run---"+i);
}
}
}
class D11TheradDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
d.start();//开启线程并执行该线程的run方法。
d.run();//仅仅是对象的函数调用,而线程创建了,并没有运行。
//
for (int i=0;i<100;i++ )
{
System.out.println("---mian run---"+i);
}
}
}
/*
练习: 创建两个线程和主线程交替运行
通过 this.getName()或Thread.currentThread() 方法可以获取线程名称
*/
class D11Test1 extends Thread
{
public void run()
{
for (int i=0;i<30;i++ )
{
System.out.println(getName()+"---run---"+i);
}
}
}
class D11Test2 extends Thread
{
public void run()
{
for (int i=0;i<30;i++ )
{
System.out.println(getName()+"---run---"+i);
}
}
}
class D11Test3 extends Thread
{
public void run()
{
for (int i=0;i<30;i++ )
{
System.out.println(getName()+"---run---"+i);
}
}
}
class D11TheradTestDemo
{
public static void main(String[] args)
{
D11Test1 t1 = new D11Test1();
t1.start();
D11Test2 t2 = new D11Test2();
t2.start();
D11Test3 t3 = new D11Test3();
t3.start();
for (int i=0;i<30;i++ )
{
System.out.println("---mian run---"+i);
}
}
}
/*
练习2
需求:简单的买票程序。
多个窗口同时买票。
创建线程的第二种方法,实现 Runnable 接口
步骤
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法。
将线程要运行的代码存放在run方法中)
3.通过Thread类建立线程对象。
4.将Runnable接口的子类对象作为实际参数给Thread类的构造函数。
自定义的run方法所属的对象时Runnable接口的子类对象,所以要让线程调用指定对象的run方法,就必须明确该run方法的对象。
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
两种方式的区别:
Runnable方式:
1.避免的单继承的局限性,在定义线程是建议使用该方式。
2.线程代码存在Runnable子类的run方法中
继承Thread方式:
1.有局限性,因为Java的单继承特性如果继承可Thread类限制了继承其他类。
2.线程带代码存放在Thread子类的run方法中。
*/
class D11Ticket implements Runnable//Thread
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick >0)
{
/*
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
*/
/*
通过上面代码 Thread.sleep(10); 分析发现 打印出 0 -1 -2 等错票
多线程的运行出现的安全问题。
问题的原因:
当多条语句在操作同一个线程共享数据时,
一个线程对多条语句执行了一部分,还没有执行完毕时,
另一个线程参与进来执行,导致共享数据的错误。
解决方法:
对于多条操作的共享数据的语句,只能让一个线程都执行完毕。
在一个线程执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了一个同步代码块用于解决这种问题。
格式如下:
synchronized(对象)
{
}
*/
System.out.println(Thread.currentThread().getName()+" Sale :"+ tick --);
}
}
}
}
class D11TicketDemo
{
public static void main(String[] args)
{
D11Ticket t1 = new D11Ticket();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
}
}
/*
Java对于多线程的安全问题提供了一个同步代码块用于解决这种问题。
格式如下:
synchronized(对象)
{
}
对象如同锁,持有锁的线程可以再同步中执行,
没有持有锁的线程即使获取到CPU的执行权,也进不去,因为没有锁。
同步的前提:
1.必须要有两个或者两个以上的线程。
2.必须是多个线程使用同一个锁。
同步的利弊:
利:保证只用一个线程在执行,解决了多线程中多条语句在操作同一个线程共享数据时的安全问题。
弊:多个线程都需要判断锁,较为消耗资源。
*/
class D11Ticket2 implements Runnable//Thread
{
private int tick = 100;
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()+" Sale :"+ tick --);
}
}
}
}
}
class D11TicketDemo2
{
public static void main(String[] args)
{
D11Ticket2 t1 = new D11Ticket2();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
new Thread(t1).start();
}
}
/*
练习3
需求:
银行有一个金库
有两个存户分别存300斤黄金,每次存100斤,存3次。
目的: 该程序是否有安全问题,如果有,如何解决?
如何找问题:
1.明确哪些代码是多线程执行代码。
2.明确哪些是共享数据。
3.明确多线程运行代码中哪些语句是操作共享数据的。
*/
class D11Bank
{
private int sum;
//同步函数也可以解决这种问题。
public synchronized void add(int n)
{
sum +=n;
//
try{Thread.sleep(1000);}catch (Exception e){}
System.out.println("sum="+ sum);
}
}
class D11Cus implements Runnable
{
private D11Bank b = new D11Bank();
public void run()
{
for(int i =0; i<3 ;i++ )
{
b.add(100);
}
}
}
class D11BankDemo
{
public static void main(String[] args)
{
D11Cus c = new D11Cus();
//
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
//
t1.start();
t2.start();
}
}
/*
同步函数用的是哪一个锁呢?
函数需要被对象调用,那么函数都有一个所属对象引用,就是this。
所以同步函数使用的锁是this
下面通过该程序进行验证:
使用线程来卖票
一个线程在同步代码中,一个线程在同步函数中。
都在执行卖票动作
*/
class D11Ticket3 implements Runnable//Thread
{
private int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(this)
{
if(tick >0)
{
try{Thread.sleep(10);}catch (Exception e){}
//
System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --);
}
}
}
}
else
{
while(true)
{
show();
}
}
}
public synchronized void show()
{
if(tick >0)
{
try{Thread.sleep(10);}catch (Exception e){}
//
System.out.println(Thread.currentThread().getName()+" function Sale :"+ tick --);
}
}
}
class D11TicketDemo3
{
public static void main(String[] args)
{
D11Ticket3 t = new D11Ticket3();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
//
t1.start();
try{Thread.sleep(10);}catch (Exception e){}
t.flag =false;
t2.start();
}
}
/*
如果同步函数被static修饰后,使用的锁是什么呢?
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
类名.class 该对象的类型是Class
所以
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class
*/
class D11Ticket4 implements Runnable//Thread
{
private static int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
//synchronized(obj)
synchronized(D11Ticket4.class)
{
if(tick >0)
{
try{Thread.sleep(20);}catch (Exception e){}
//
System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --);
}
}
}
}
else
{
while(true)
{
show();
}
}
}
public static synchronized void show()
{
if(tick >0)
{
try{Thread.sleep(10);}catch (Exception e){}
//
System.out.println(Thread.currentThread().getName()+" function Sale :"+ tick --);
}
}
}
class D11TicketDemo4
{
public static void main(String[] args)
{
D11Ticket4 t = new D11Ticket4();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
//
t1.start();
try{Thread.sleep(10);}catch (Exception e){}
t.flag =false;
t2.start();
}
}
/*
重提 单例设计模式
*/
/*
//饿汉式
class Single
{
private static final Single s =new Single();
private Single();
public static Single getInstance()
{
return s;
}
}
*/
//懒汉式
class D11Single
{
private static D11Single s =null;
private D11Single(){}
public static D11Single getInstance()
{
//双重判断
if(s == null)
{
synchronized(D11Single.class)
{
if(s == null)
{
s = new D11Single();
}
}
}
return s;
}
}
/*
死锁
同步中嵌套同步
*/
class D11Ticket5 implements Runnable//Thread
{
private static int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(D11Ticket4.class)
{
show();
}
}
}
else
{
while(true)
{
show();
}
}
}
public static synchronized void show()
{
synchronized(D11Ticket4.class)
{
if(tick >0)
{
try{Thread.sleep(20);}catch (Exception e){}
//
System.out.println(Thread.currentThread().getName()+" code Sale :"+ tick --);
}
}
}
}
class D11TicketDemo5
{
public static void main(String[] args)
{
D11Ticket5 t = new D11Ticket5();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
//
t1.start();
try{Thread.sleep(10);}catch (Exception e){}
t.flag =false;
t2.start();
}
}
class D11TestLock implements Runnable
{
private boolean flag;
D11TestLock(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
synchronized(D11MyLock.locka)
{
System.out.println("if locka");
synchronized(D11MyLock.lockb)
{
System.out.println("if lockb");
}
}
}
else
{
System.out.println("else lockb");
synchronized(D11MyLock.lockb)
{
synchronized(D11MyLock.locka)
{
System.out.println("else locka");
}
}
}
}
}
class D11MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
}
class D11DeadLockTest
{
public static void main(String[] args)
{
Thread t1 = new Thread(new D11TestLock(true));
Thread t2 = new Thread(new D11TestLock(false));
//
t1.start();
t2.start();
}
}
Day12
/*
线程间通讯
其实就是多个线程在操作同一个资源
但是操作的动作不同
wait();线程存储在线程池中
notify();唤醒线程池中的线程,通常唤醒顶部的线程。
notifyAll();;唤醒线程池中所有的线程
这些作线程的方法要使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁。
只有同一个锁上的被wait()的线程,才可以被同一个锁上的notify()唤醒线程,不可以对不同锁中的线程进行唤醒。
(也就是说,等待和唤醒线程的必须是同一个锁。)
因为锁可以使任意对象,所以可以被任意对象调用的方法只能有Object,所以定义在Object类中。
*/
import java.util.concurrent.locks.*;
class D12Res
{
String name;
String sex;
boolean flag = false;
}
class D12Input implements Runnable
{
private D12Res r;
D12Input(D12Res r)
{
this.r = r ;
}
public void run()
{
int i=0;
while(true)
{
synchronized(r)
{
if(r.flag)
try{r.wait();}catch (Exception e){}
if(i%2==0)
{
r.name ="tom";
r.sex = "man";
}
else
{
r.name ="赫尔";
r.sex = "女";
}
i++;
r.flag =true;
//唤醒OutPut
r.notify();
}
}
}
}
class D12Output implements Runnable
{
private D12Res r;
D12Output(D12Res r)
{
this.r = r ;
}
public void run()
{
while(true)
{
synchronized(r)
{
if(!r.flag)
try{r.wait();}catch (Exception e){}
System.out.println(r.name+" "+r.sex);
//
r.flag =false;
r.notify();
}
}
}
}
class D12InPutAndOutPutDemom
{
public static void main(String[] args)
{
D12Res r = new D12Res();
D12Input in = new D12Input(r);
D12Output out = new D12Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
/*
改进D12Res
*/
class D12Res2
{
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name, String sex )
{
if(flag)
try{this.wait();}catch (Exception e){}
this.name = name ;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch (Exception e){}
System.out.println(this.name+" "+this.sex);
flag = false;
this.notify();
}
}
class D12Input2 implements Runnable
{
private D12Res2 r;
D12Input2(D12Res2 r)
{
this.r = r ;
}
public void run()
{
int i=0;
while(true)
{
if(i%2==0)
r.set("tom" ,"man");
else