----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1.创建线程的两种常用方法
创建线程的第二种方法:
1,定义类实现Runnable接口
2.覆盖Runnable接口中的run方法
3.通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造器
5.调用Thread;类的start方法开启线程并调用Runnable接口子类的run方法.
实现方式和继承方式的区别?
实现方式的好处是避免了单继承的局限性,在定义线程时建议使用实现方式
两种方法区别:
继承Thread:线程代码存放在Thread子类的run方法中
实现Runnable接口,代码存放在接口的run方法中
第一种方法代码:
class ThreadDemo1//演示创建线程的方法一继承Thread类
{
public static void main(String[] args)
{
MyThread1 m1=new MyThread1();
MyThread1 m2=new MyThread1();
MyThread1 m3=new MyThread1();
m1.start();
m2.start();
m3.start();
}
}
class MyThread1 extends Thread
{
private static int num=100;
public void run()
{
while(num>0)
{
System.out.println("当期线程: "+Thread.currentThread().getName()+"num: "+num--);
}
}
}
第二种方法:代码
class ThreadDemo2//创建线程的方法二 实现Runnable接口
{
public static void main(String[] args)
{
MyThread mt1=new MyThread();
MyThread mt2=new MyThread();
MyThread mt3=new MyThread();
Thread th1=new Thread(mt1);
Thread th2=new Thread(mt2);
Thread th3=new Thread(mt3);
th1.start();
th2.start();
th3.start();
}
}
class MyThread implements Runnable
{
private static int num=100;
public void run()//覆写run()方法
{
while(num>0)
{
System.out.println(Thread.currentThread().getName()+" num="+num--);
}
}
}
2.多线程基本知识
同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
同步函数的锁是this
静态函数的锁是Class对象
为什么这些操作线程的方法,wait(),notify(),notifyAll()要定义在Object类中.?因为这些方法在操作同步中线程时,都必须要标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒.不可以对不同锁中的线程进行唤醒.
也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中.
JDK1.5 中提供了多线程升级解决方案.
将同步synchronized替换成现实lock操作.
将object中的wait,notify notifyAll,替换了condition对象
该对象可以lock锁 进行获取.
实现本方唤醒对方的机制.
线程停止的方法:
之前用stop方法,后来就不再使用了,
目前只有一个方法就是run()方法的结束.
3.一个死锁的例子
class DeadLockDemo//演示死锁
{
public static void main(String[] args)
{
DeadLock d=new DeadLock();
Thread t1=new Thread(d);
Thread t2=new Thread(d);
t1.start();
t2.start();
}
}
class DeadLock implements Runnable
{
Object lock1=new Object();
Object lock2=new Object();
boolean flag=true;
public void run()
{
if(flag)
{
flag=false;
synchronized(lock1)
{
System.out.println("lock1");
synchronized(lock2)
{
System.out.println("if lock2");
}
}
}
else
{
flag=true;
synchronized(lock2)
{
System.out.println("else lock2");
synchronized(lock1)
{
System.out.println("else lock1");
}
}
}
}
}
4.线程间通信
线程间通信其实就是多线程操作同一个资源
wait与sleep的区别:
sleep只释放资源不释放锁
wait即释放资源又释放锁
生产与消费的一个代码例子:
class InputOutputDemo//进程间通信演示代码
{
public static void main(String[] args)
{
Res s=new Res();
Input in=new Input(s);
Output out=new Output(s);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
class Res//资源类
{
public String name;
public String sex;
}
class Input implements Runnable//生产者
{
private Res r;
public Input(Res r)
{
this.r=r;
}
public void run()
{
boolean flag=true;
while(true)
{
synchronized("haha")
{
if(flag)
{
flag=false;
r.name="mike";
r.sex="man";
}else
{
flag=true;
r.name="丽丽";
r.sex="女";
}
}
}
}
}
class Output implements Runnable//消费者
{
private Res r;
public Output(Res r)
{
this.r=r;
}
public void run()
{
boolean flag=true;
while(true)
{
synchronized("haha")
{
if(flag)
{
flag=false;
System.out.println(r.name+": "+r.sex);
}else
{
flag=true;
System.out.println(r.name+": "+r.sex);
}
}
}
}
}
等待唤醒机制对上面的生产者与消费者就行优化:
join方法的特点:
当A线程执行到了B线程的join方法时,A就会等待,等B线程都执行完,A才会执行.join可以用来临时加入线程.
4.1线程间通信JDK1.5后新方法
import java.util.concurrent.locks.*;
class ProConDemo2//演示生产者消费者
{
public static void main(String[] args)
{
Resource2 r=new Resource2();
Producer2 pro=new Producer2(r);
Consumer2 con=new Consumer2(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
Thread t3=new Thread(pro);
Thread t4=new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource2//d
{
private String name;
private int count=1;
private boolean flag=false;
private Lock lock=new ReentrantLock();//since JDK1.5
private Condition condition_pro=lock.newCondition();
private Condition condition_con=lock.newCondition();
public void set(String name) throws Exception
{
lock.lock();
try
{
while(flag)
condition_pro.await();
this.name=name+(count++);
System.out.println("生产了:"+this.name);
flag=true;
condition_con.signal();
}
finally
{
lock.unlock();///
}
}
public void out()throws Exception
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println("消费了.............."+this.name);
flag=false;
condition_pro.signal();
}
finally{lock.unlock();} ///
}
}
class Producer2 implements Runnable
{
private Resource2 r;
public Producer2(Resource2 r)
{
this.r=r;
}
public void run()
{
while(true)
{
try
{
r.set("商品");
}
catch (Exception e){}
}
}
}
class Consumer2 implements Runnable
{
private Resource2 r;
public Consumer2(Resource2 r)
{
this.r=r;
}
public void run()
{
while(true)
{
try
{
r.out();
}
catch (Exception e){}
}
}
}
5.图形化界面实现多窗口售票功能
说明:利用多线程做的模拟售票系统.为了真实的演示,为程序增加了图形化界面.界面如下图所示.有四个子线程分别代表四个窗口进行售票.四个售票窗口共同拥有一个票库.
import java.awt.*;
import java.awt.event.*;
class SaleTicketDemo//演示可视化界面售票类
{
public static void main(String[] args)
{
new SaleTicket(1000).start();
}
}
class SaleTicket //售票类
{
private Frame frame=new Frame("售票大厅");
private TextArea window1=new TextArea("1号售票窗口",10,40,TextArea.SCROLLBARS_VERTICAL_ONLY);//定义售票窗口
private TextArea window2=new TextArea("2号售票窗口",10,40,TextArea.SCROLLBARS_VERTICAL_ONLY);//定义售票窗口
private TextArea window3=new TextArea("3号售票窗口",10,40,TextArea.SCROLLBARS_VERTICAL_ONLY);//定义售票窗口
private TextArea window4=new TextArea("4号售票窗口",10,40,TextArea.SCROLLBARS_VERTICAL_ONLY);//定义一个公布余票信息窗口
private Panel panel1=new Panel();
private Panel panel2=new Panel();
private final TextField field=new TextField(60);//定义一个显示板,用于显示余票等信息.
private Button but1=new Button("开始售票");//定义一个按钮,用于启动售票系统
private Button but2=new Button("重新设置");//清空数据,重新开始演示
private int num=1000;//定义初始化票总数
private int num2=1000;//定义该变量用于记录num,用于重新设置时.
public SaleTicket(){}//无参构造器
public SaleTicket(int num)//含参数构造器,参数为设置票总数
{
num2=num;
setNum(num);
}
public void setNum(int num)
{
if(num<0||num>10000)
{
System.out.println("您设置的票数非法.");
}else
{
this.num=num;
num2=num;
}
}
public int getNum()
{
return num;
}
public int saleNum()//每调用一次,票数少一张,并返回当前票数
{
return num--;
}
private void init()//初始化图形界面函数
{
frame.setBounds(50,50,610,410);//设置大小和位置
frame.setBackground(new Color(255,218,185));
frame.setLayout(new FlowLayout());
but1.setForeground(new Color(148, 0, 211));
window1.setForeground(new Color(255,7,211));
window2.setForeground(new Color(255,7,211));
window3.setForeground(new Color(255,7,211));
window4.setForeground(new Color(255,7,211));
field.setForeground(new Color(0,0,255));
flushNum();
frame.add(panel1);
frame.add(panel2);
panel2.setLayout(new GridLayout(2,2));
panel1.add(but2);
panel1.add(field);
panel1.add(but1);
panel2.add(window1);
panel2.add(window2);
panel2.add(window3);
panel2.add(window4);
//为窗口增加关闭监听器
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
frame.setVisible(true);
but1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
flushNum();
System.out.println(e.toString());
saleTicket();
}
});
but2.setForeground(new Color(255,0,0));
but2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
window1.setText("");
window2.setText("");
window3.setText("");
window4.setText("");
setNum(num2);
flushNum();
System.out.println(e.toString());
}
});
}
public void start()//开始运营系统,是该类的如楼函数
{
init();
}
class Window1 implements Runnable//窗口1类,用于出售票方法
{
int temp=1;
public void run()
{
window1.setForeground(new Color(255,0,0));
while(getNum()>0)
{
synchronized(SaleTicket.class)
{
window1.append("1#窗口售出票号:"+(saleNum()+1)+"\r\n"+"累计售出: "+(temp++)+"\r\n");
}
flushNum();
}
window1.append("对不起,票已经售完,该窗口今天累计售出:"+(temp-1)+"张票");
}
}
class Window2 implements Runnable//窗口2类
{
int temp=1;
public void run()
{
window2.setForeground(new Color(120,5,250));
while(getNum()>0)
{
synchronized(SaleTicket.class)
{
window2.append("2#窗口售出票号:"+(saleNum()+1)+"\r\n"+"累计售出: "+(temp++)+"\r\n");
}
flushNum();
}
window2.append("对不起,票已经售完,该窗口今天累计售出:"+(temp-1)+"张票");
}
}
class Window3 implements Runnable//窗口2类
{
int temp=1;
public void run()
{
while(getNum()>0)
{
synchronized(SaleTicket.class)
{
window3.append("3#窗口售出票号:"+(saleNum()+1)+"\r\n"+"累计售出: "+(temp++)+"\r\n");
}
flushNum();
}
window3.append("对不起,票已经售完,该窗口今天累计售出:"+(temp-1)+"张票");
}
}
class Window4 implements Runnable//窗口2类
{
int temp=1;
public void run()
{
window4.setForeground(new Color(0,0,255));
while(getNum()>0)
{
synchronized(SaleTicket.class)
{
window4.append("4#窗口售出票号:"+(saleNum()+1)+"\r\n"+"累计售出: "+(temp++)+"\r\n");
}
flushNum();
}
window4.append("对不起,票已经售完,该窗口今天累计售出:"+(temp-1)+"张票");
}
}
private void saleTicket()//开始售票
{
Window1 w1=new Window1();
Window2 w2=new Window2();
Window3 w3=new Window3();
Window4 w4=new Window4();
Thread t1=new Thread(w1);
Thread t2=new Thread(w2);
Thread t3=new Thread(w3);
Thread t4=new Thread(w4);
t1.start();
t2.start();
t3.start();
t4.start();
}
private void flushNum()//刷新剩余票数
{
if(getNum()<=0)
field.setText("对不起,北京--上海的车票已经售完.");
else
field.setText("还有票数 "+getNum()+"张 北京--上海");
}
}
下图是该程序运行时状态.
下图为运行结束即票资源售完后截图.