>>3内部class类继承Thread的线程实现方式
public class TestThread
{
public static void main(String[] args)
{
//实现Runnable接口得线程实现方式 用与和内部类比较
MyThread myt1 = new MyThread();
//new Thread(myt).start()的理解:根据myt对象,实例化一个线程对象,并开始线程
new Thread(myt1).start();
//内部类继承Thread类的线程实现方式
MyThread2 myt = new MyThread2();
//由于内部类继承Thread类,所以可以使用start方法,但是方式很特别
myt.new InnerThread().getThread().start();
System.out.println("main方法线程名字:"+Thread.currentThread().getName());
}
}
//实现Runnable接口的 实现线程的方法
class MyThread implements Runnable
{
public void run()
{
System.out.println("实现Runnable接口子线程得名字:"+Thread.currentThread().getName());
}
}
//内部类继承Thread类 实现线程 赞成频繁使用
class MyThread2
{
//定义内部类:1内部类继承Thread类或实现Runnable接口,覆盖run方法 2提供一个返回值是Thread的方法,返回内部类的对象 class InnerThread extends Thread
{
public void run()
{
System.out.println("内部类输出线程名称:"+Thread.currentThread().getName());
}
}
//返回值为线程类型的方法 实例化并返回内部类 (内部类实现线程的关键)Thread getThread()
public Thread getThread
{
return new InnerThread();
}
}
>>4线程同步(synchronized)得实现:同步块和同步方法
public class TestThread
{
public static void main(String[] args)
{
//四个线程同时销售100张票
//同步块实现售票
//SellThread myt = new SellThread();
//new Thread(myt).start();//开启第一个窗口开始售票 即开启一个线程对同步对象惊醒操作 实现了共享数据同步操作
//new Thread(myt).start();//开启第二个窗口开始售票 即开启一个线程对同步对象惊醒操作
//new Thread(myt).start();//开启第三个窗口开始售票 即开启一个线程对同步对象惊醒操作
//new Thread(myt).start();//开启第四个窗口开始售票 即开启一个线程对同步对象惊醒操作
//同步方法实现售票
SellThread1 myt1 = new SellThread1();
new Thread(myt1).start();//开启第一个窗口开始售票
new Thread(myt1).start();//开启第二个窗口开始售票
new Thread(myt1).start();//开启第三个窗口开始售票
new Thread(myt1).start();//开启第四个窗口开始售票
}
}
//同步块 对某一个对象Ojbect进行加锁
class SellThread implements Runnable
{
int tickets= 100;//100张票
Object obj = new Object();//同步变量
public void run()
{
while(true)
{
//给obj对象加锁,直到同步块结束,“{”表示给obj对象加锁,"}"表示给obj对象解锁
synchronized(obj)
{
if(tickets>0)
{
//sleep是Thread类的静态方法,调用时会抛出异常,需要捕获。
try{
Thread.sleep(10);
}catch(Exception e)
{
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
/*错误的方法:先锁住对象,在while循环,最终只走一个线程(与上边对比:先while再synchronized)
//同步块
synchronized(this)
{
while(tickets>0)
{
try{
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"sells tickets==="+tickets);
tickets--;
}
}
*/
}
}
}
//同步方法 对this加锁
class SellThread1 implements Runnable
{
int tickets= 100;//100张票
//run方法调用同步方法sell
public void run()
{
sell();
}
//声明同步方法的关键字:synchronized
public synchronized void sell()
{
while(true)
{
if(tickets>0)
{
try{
Thread.sleep(10);
}catch(Exception e)
{
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
}
}
>>5 同步块和同步方法实现共享数据的同步
public class TestThread
{
public static void main(String[] args)
{
//同步块和同步方法实现共享数据的同步(特点:同步块的同步对象为this,如果同步对象是obj,则会出现index=0)
SellThread myt1 = new SellThread();
new Thread(myt1).start();//开启第一个窗口开始售票 启动第一个线程
try{
Thread.sleep(1);//主线程休眠
}
catch(Exception e)
{
e.printStackTrace();//sleep方法会抛出异常,所以需要捕获
}
myt1.bFlag = true;//改变bFlag得值为true
new Thread(myt1).start();//开启第二个窗口开始售票
}
}
//对某一个Object对象进行加锁
class SellThread implements Runnable
{
int tickets= 100;//100张票
Object obj = new Object();//同步变量
boolean bFlag = false;//同步方法和同步块转换的条件
public void run()
{
if(bFlag==false)
{
while(true)
sell();
}else {
while(true)
{
//同步块
synchronized(this)
{
if(tickets>0)
{
try{
Thread.sleep(10);
}
catch(Exception e){
e.printStackTrace();
}
System.out.println("同步块线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
}
}
}
//同步方法
public synchronized void sell()
{
if(tickets>0)
{
try{
Thread.sleep(10);
}
catch(Exception e){
e.printStackTrace();
}
System.out.println("同步方法线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
}
>>6线程同步时发生的死锁
线程A和B,A的同步对象m,n,B的同步也是对象m,n,进程A运行时先锁住m,进程B运行时先锁住n,A进程要用到n对象能完成但是n已经被B锁住,所以进程A进入等待状态,B进程要用到m对象才能完成但是m对象已经被A锁住,所以进程B也进入等待状态,出现死锁。
《红色标记为出现死锁得代码,注意与上例的比较》
public class TestThread
{
public static void main(String[] args)
{
SellThread myt1 = new SellThread();
new Thread(myt1).start();//开启第一个窗口开始售票
try{
Thread.sleep(1);//主线程休眠
}
catch(Exception e)
{
e.printStackTrace();//sleep方法会抛出异常,所以需要捕获
}
myt1.bFlag = true;//改变b得值为true
new Thread(myt1).start();//开启第二个窗口开始售票
}
}
//对某一个对象进行加锁
class SellThread implements Runnable
{
int tickets= 100;//100张票
Object obj = new Object();//同步变量
boolean bFlag = false;
public void run()
{
if(bFlag==false)
{
while(true)
sell();
}else
{
while(true)
{
//同步块
synchronized(obj)
{
try{
Thread.sleep(10);
}
catch(Exception e){
e.printStackTrace();
}
synchronized(this)
{
if(tickets>0)
{
System.out.println("同步块线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
}
}
}
}
//同步方法
public synchronized void sell()
{
synchronized(obj)
{
if(tickets>0)
{
try{
Thread.sleep(10);
}
catch(Exception e){
e.printStackTrace();
}
System.out.println("同步方法线程:"+Thread.currentThread().getName()+"sell==="+tickets);
tickets--;
}
}
}
}
>>7"生产者--消费者"模型 " 等待--通知(wait---notify)"模型。 一定是同步方法且作用同一个对象
public class TestThread
{
public static void main(String[] args)
{
MyQueue q = new MyQueue();
//创建生产者
Producer p = new Producer(q);
//创建消费者
Consumer c = new Consumer(q);
//开始成产
p.start();
//k开始消费
c.start();
}
}
//树洞类 存放和取走数据
//存放和取走得方法都是同步的方法,且针对同一个变量value
class MyQueue
{
//数据变量value
int value =0;
//标记数据是否被取走得变量bFull
boolean bFull = false;
//消费者获得数据得方法
synchronized int get()
{
//如果不是满的,也就是没有数据,则等待生产者放入数据
if(!bFull)
{
try
{
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
//改变是否取走数据得状态标记的值
bFull = false;
//通知生产者,放入数据
notify();
//返回数据,消费者取走数据
return value;
}
//生产者放入数据的方法
synchronized void set(int intValue)
{
//如果数据不是满的,也就是数据被消费者取走了,则放入数据
if(!bFull)
{
//生产者放入数据
this.value = intValue;
//改变数据是否被取走得标记
bFull = true;
//通知消费者来取数据
notify();
}
//如果数据是满的,也就是消费者还没哟取数据,则等待消费折取走数据
try{
wait();
}
catch(Exception e){
e.printStackTrace();
}
}
}
//生产者类---情报员
class Producer extends Thread
{
MyQueue q;
Producer(MyQueue q)
{
this.q = q;
}
public void run()
{
for(int i=0;i<10;i++)
{
q.set(i);
System.out.println("set==="+i);
}
}
}
//消费者类 ---情报员
class Consumer extends Thread
{
MyQueue q;
Consumer(MyQueue q)
{
this.q = q;
}
public void run()
{
while(true)
{
System.out.println("get====="+q.get());
}
}
}
>>7终止线程得方法:1变量控制
public class TestThread
{
public static void main(String[] args)
{
Consumer c = new Consumer();
c.start();
int index =0;
while(true){
if(index++==500)
{
c.stopThread();//改变while循环的变量条件
break; //终止线程
}
System.out.println("main名字:"+Thread.currentThread().getName()+"index===="+index);
}
//程序结束输出
System.out.println("main exit()");
}
}
class Consumer extends Thread
{
//while循环的条件变量
private boolean bStop = false;
public void run()
{
while(!bStop)
{
System.out.println("子线程名字:"+getName());
}
}
//关闭线程的方法:改变while循环变量得条件
public void stopThread()
{
this.bStop = true;
}
}
>>8带有wait方法的线程关闭方法2 :interrupt方法
public class TestThread
{
public static void main(String[] args)
{
Consumer c = new Consumer();
c.start();
int index =0;
while(true){
if(index++==500)
{
c.stopThread();//改变while循环的变量条件 终止线程
c.interrupt(); //关闭线程
break;
}
System.out.println("main名字:"+Thread.currentThread().getName()+"index===="+index);
}
//程序结束输出
System.out.println("main exit()");
}
}
class Consumer extends Thread
{
//while循环的条件变量
private boolean bStop = false;
//wait方法一定要在静态方法或者静态块中
public synchronized void run()
{
while(!bStop)
{
try{
wait();//带有wait
}
catch(InterruptedException e)
{
//异常处理
if(bStop){
return ;
}
}
System.out.println("子线程名字:"+getName());
}
}
//关闭线程的方法:改变while循环变量得条件
public void stopThread()
{
this.bStop = true;
}
}
>>一个完整的内部类例子
//内部类实现
public class SellTicket
{
private int tickets=100;
public SellTicket ()
{}
//内部类,继承Thread
class Sellor extends Thread
{
//重写run方法
public void run()
{
synchronized(this)
{
while(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"sells tickets====="+tickets);
tickets--;
}
}
}
//方法返回值为Thread,返回内部类自己的实体对象(因为内部类已经继承了Thread或者实现了Runnable接口)
public Thread getSellor()
{
return new Sellor();
}
}
public static void main(String[] args)
{
SellTicket sell = new SellTicket();
//调用内部类的线程并启动run方法
sell.new Sellor().getSellor().start();
}
}
>>关于重写run方法的理解
一个类继承自Thread,此时可以不重写run方法,就等于使用Thread的run方法,run(){}方法是空的,所以没有意义但是不会出错;
一个类实现了 Runnable接口必须实现run方法,这是实现接口要求的,否则会出错