是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。
并发性、共享性、动态性和结构性
a、Runnable接口(里面就一个run方法,只要通过重写run方法就可以实现自己想要的线程功能)
public interface Runnable { public abstract void run(); }b、Thread线程类(继承这个类)
public class Thread extends Object implements Runnable { public Thread() //构造方法 public Thread(String name) //name指定线程名 public Thread(Runnable target) //target指定线程的目标对象 public Thread(Runnable target, String name) public void run() //描述线程操作的线程体 public final String getName() //返回线程名 public final void setName(String name) //设置线程名 public static int activeCount() //返回当前活动线程个数 public static Thread currentThread() //返回当前执行线程对象 public Sting toString() //返回线程的字符串信息 public void start() //启动已创建的线程对象 }
a、线程启动:
public void start() //启动线程对象 public final boolean isAlive() //是否启动b、线程睡眠:
public static void sleep(long millis) throws InterruptedExceptionc、线程中断:
public void interrupt() //设置中断标记 public boolean isInterrupted() //判断是否中断 public static boolean interrupted() //判断是否中断
a、Thread类中声明了3个表示优先级的公有静态常量:
public static final int MIN__PRIORITY=1 //最低优先级 public static final int MAX_PRIORITY=10 //最高优先级 public static final int NORM_PRIORITY=5 //默认优先级b、Thread类中与线程优先级有关的方法2种:
public final int getPriority() //获得线程优先级 public final void setPriority(int newPriority)//设置线程优先级
public class Timer implements Serializable { public Timer(int delay, ActionListener l) public void addActionListener(ActionListener l) //注册定时事件监听器 public void setDelay(int delay) //设置延时的时间间隔 public void start() //启动定时器 public void stop() //停止定时器 public void restart() //重新启动定时器 }
package p25.cooperate; public class Buffer { private int value; public void put(int value){ this.value = value; } public int get(){ return this.value; } } class SendThread extends Thread{ private Buffer buffer; public SendThread(Buffer buffer){ this.buffer = buffer; } @Override public void run() { for(int i=1; i<=5; i++){ buffer.put(i); System.out.println(this.getClass().getName()+"put:"+i); } } } class ReceiveThread extends Thread{ private Buffer buffer; public ReceiveThread(Buffer buffer){ this.buffer = buffer; } @Override public void run() { for(int i=1; i<=5; i++){ int num = buffer.get(); System.out.println("\t\t\t"+this.getClass().getName()+"get:"+num); } } } class Run{ public static void main(String[] args) { Buffer buffer = new Buffer(); (new SendThread(buffer)).start(); (new ReceiveThread(buffer)).start(); } }结果:
package p24; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; public class WelcomeJFrame extends JFrame { public WelcomeJFrame(String[] texts){ super("流动字"); this.setBounds(300, 240, 500, 400); this.setDefaultCloseOperation(EXIT_ON_CLOSE); if(texts==null || texts.length==0){ this.getContentPane().add(new RollbyJPanel("Welcome!")); }else{ this.getContentPane().setLayout(new GridLayout(texts.length, 1)); for(int i=0;i<texts.length;i++){ this.getContentPane().add(new RollbyJPanel(texts[i])); } } this.setVisible(true); } public WelcomeJFrame(){ this(null); } private class RollbyJPanel extends JPanel implements Runnable,ActionListener{ JTextField textWord,textSleep,textState; int sleeptime; JButton btnStart,btnInterrupt; Thread t; RollbyJPanel(String text) { this.setLayout(new GridLayout(2, 1)); char[] space = new char[60]; textWord = new JTextField(text+new String(space)); this.add(textWord); JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT)); this.add(p); p.add(new JLabel("sleep:")); this.sleeptime = (int) (Math.random()*100); textSleep = new JTextField(""+sleeptime,5); p.add(textSleep); textSleep.addActionListener(this); btnStart = new JButton("启动"); p.add(btnStart); btnStart.addActionListener(this); btnInterrupt= new JButton("中断"); p.add(btnInterrupt); btnInterrupt.addActionListener(this); t = new Thread(this); t.start(); btnStart.setEnabled(false); p.add(new JLabel("state:")); textState = new JTextField(""+t.getState(),10); textState.setEditable(false); p.add(textState); } public void actionPerformed(ActionEvent e) { if(e.getSource()==textSleep){ updateSleeptime(); } if(e.getSource()==btnStart){ updateSleeptime(); t = new Thread(this); t.start(); btnStart.setEnabled(false); btnInterrupt.setEnabled(true); textState.setText("运行ing..."); //textState.setText(""+t.getState()); } if(e.getSource()==btnInterrupt){ t.interrupt(); btnStart.setEnabled(true); btnInterrupt.setEnabled(false); textState.setText(""+t.getState()); } } private void updateSleeptime() { try { sleeptime = Integer.parseInt(textSleep.getText()); if(sleeptime<0){ sleeptime=0; textSleep.setText(""+0); } } catch (NumberFormatException e1) { //e1.printStackTrace(); JOptionPane.showMessageDialog(this, "\""+ textSleep.getText()+"\"不能转换成整数,请重新输入"); } } public void run() { while (true) { try { String str = textWord.getText(); str = str.substring(1) + str.substring(0, 1); textWord.setText(str); Thread.sleep(sleeptime); } catch (InterruptedException e) { break;//e.printStackTrace(); } } } } public static void main(String[] args) { String[] strs={"Welcome","Hello","Rollby","aaaa","yyyy"}; //new WelcomeJFrame(strs); new WelcomeJFrame(); } }结果:
a、多线程互斥共享“基本数据类型数据”资源:多线程的互斥共享资源----为基本数据类型时,不能直接当作互斥锁。解决方案:造一个与基本数据
类型资源平等的对象,来当作互斥锁。
b、多线程互斥共享“栈”资源
例子3:多窗口卖票
package p51; public class ThreadSynDemo1 { public static void main(String[] args) { Thread t1 = new Thread(new Ticket("卖票窗口1")); Thread t2 = new Thread(new Ticket("卖票窗口2")); Thread t3 = new Thread(new Ticket("卖票窗口3")); Thread t4 = new Thread(new Ticket("卖票窗口4")); t1.start(); t2.start(); t3.start(); t4.start(); //Person p1 = new Person("wjf",22,"jkkkj"); //Person p2 = new Person("yc",23,"aaaaa"); //p1.name p2.name //p1.room="a12345"; p2.room /* * class Person{ * String name; * int age; * String info; * static String room; * } * */ } } class Ticket implements Runnable { private static int num = 200;// 多线程的互斥共享资源----为基本数据类型时,不能直接当作互斥锁 private static Object obj = new Object();// 解决方案:造一个与基本数据类型资源平等的对象,来当作互斥锁 private String name; public Ticket(String name) { this.name = name; } public void run() { while (true) { synchronized (obj) { //※此处,obj不能用this来代替 int ticketNum = num;// 拿到票号 // 中间模拟一些卖票所需的手续,耗费时间随机 int rand = (int) (Math.random() * 10); try { Thread.sleep(rand); } catch (Exception e) { } if (num > 0) { System.out.println(name + ":" + ticketNum);// 给出票 num--; } else { break; } } } } }
a、java的多线程是抢占式的运行方式。
b、setPriority():设置优先级
package p51.schedule; public class Schedule { //演示线程调度中的setPriority()方法 //演示线程调度中的interrupt()方法 public static void main(String[] args) { Thread t1 = new MyRunner(); Thread t2 = new MyRunner(); <span style="color:#ff0000;">t1.setPriority(9); t2.setPriority(3);</span> t1.start(); t2.start(); try{ Thread.sleep(2000); }catch (Exception e) { } //t1.interrupt();//强制唤醒 } } class MyRunner extends Thread{ public void run(){ int i=0; System.out.println(Thread.currentThread().getName()+"is sleep..."); try{ Thread.sleep(10000); }catch (Exception e) { } for(;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"No:"+i); } } }
c、sleep()方法:Thread类的sleep()方法对当前线程操作,是静态方法。sleep()的参数指定以毫秒为单位的线程休眠时间。除非因为中断而
提早恢复执行,否则线程不会在这段时间之前恢复执行。
package p51.schedule.s1; public class Schedule { //演示线程调度中的sleep()方法 public static void main(String[] args) { Thread t1 = new MyRunner(1); Thread t2 = new MyRunner(2); //t1.setPriority(9); //t2.setPriority(3); t1.start(); t2.start(); } } class MyRunner extends Thread{ int num; public MyRunner(int num) { this.num = num; } public void run(){ int i=0; System.out.println(Thread.currentThread().getName()+"is sleep..."); try{ if(num==1){ <span style="color:#ff0000;">Thread.sleep(5000);</span> } }catch (Exception e) { } for(;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"No:"+i); } } }
d、interrupt()方法:一个线程可以调用另外一个线程的interrupt()方法,这将向暂停的线程发出一个InterruptedException。变相起到唤醒暂停
线程的功能。Thread类的方法interrupt(),是一种强制唤醒的技术。
package p51.schedule; public class Schedule { //演示线程调度中的setPriority()方法 //演示线程调度中的interrupt()方法 public static void main(String[] args) { Thread t1 = new MyRunner(); Thread t2 = new MyRunner(); //t1.setPriority(9); //t2.setPriority(3); t1.start(); t2.start(); try{ Thread.sleep(2000); }catch (Exception e) { } <span style="color:#ff0000;">t1.interrupt();//强制唤醒</span> } } class MyRunner extends Thread{ public void run(){ int i=0; System.out.println(Thread.currentThread().getName()+"is sleep..."); try{ Thread.sleep(10000); }catch (Exception e) { } for(;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"No:"+i); } } }
e、yield()方法:用来使具有相同优先级的线程获得执行的机会。如果具有相同优先级的其它线程是可运行的,yield()将把线程放到可运行池
中并使另一个线程运行。如果没有相同优先级的可运行线程,则什么都不做。
package p51.schedule.s2; public class Schedule { //演示线程调度中的yield()方法 public static void main(String[] args) { Thread t0 = new MyRunner(1); Thread t1 = new MyRunner(2); //t1.setPriority(6);//yield()方法只能把机会让给同一优先级的其它线程,此处即使优先级设成更高,先运行的概率反倒没有不设的高 t0.start(); t1.start(); } } class MyRunner extends Thread{ int num; public MyRunner(int num) { this.num = num; } public void run(){ int i=0; System.out.println(Thread.currentThread().getName()+"is sleep..."); try{ Thread.sleep(1000); if(num==1){ <span style="color:#ff0000;">Thread.yield()</span>; num=0; } }catch (Exception e) { } for(;i<5;i++){ System.out.println(Thread.currentThread().getName()+"No:"+i); } } }
f、join()方法:调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。它可以实现线程合并的功
能,经常用于线程的绝对调度。
package p51.schedule.s3; public class Schedule { //演示线程调度中的join()方法 public static void main(String[] args) { Thread t0 = new MyRunner(1); Thread t1 = new MyRunner(2); t0.start(); try { <span style="color:#ff0000;">t0.join();</span>//把t0合并到当前线程(此处即main线程) } catch (InterruptedException e) { e.printStackTrace(); } t1.start(); } } class MyRunner extends Thread{ int num; public MyRunner(int num) { this.num = num; } public void run(){ int i=0; System.out.println(Thread.currentThread().getName()+"is sleep..."); try{ Thread.sleep(1000); if(num==1){ Thread.yield(); num=0; } }catch (Exception e) { } for(;i<5;i++){ System.out.println(Thread.currentThread().getName()+"No:"+i); } } }
g、wait()方法:当前线程进入对象的wait pool。(例1的修改)
h、notify()/notifyAll()方法:唤醒对象的wait pool中的一个/所有等待线程。
package p25.cooperate.co; public class LockBuffer { private int value; private boolean isEmpty=true;//信号量 public synchronized void put(int value){//存放 //if(!this.isEmpty){//非空 ※可能有bug,因为如果被意外唤醒,就往前执行了,不会重新判断信号量 while(!this.isEmpty){//非空 try { <span style="color:#ff0000;">this.wait();</span> } catch (InterruptedException e) { } } this.value = value; this.isEmpty = false; this.notify(); } public synchronized int get(){ while(this.isEmpty){//为空 try { this.wait(); } catch (InterruptedException e) { } } this.isEmpty=true; <span style="color:#ff0000;">this.notify();</span> return this.value; } } class SendThread extends Thread{ private LockBuffer buffer; public SendThread(LockBuffer buffer){ this.buffer = buffer; } @Override public void run() { for(int i=1; i<=5; i++){ buffer.put(i); System.out.println(this.getClass().getName()+"put:"+i); } } } class ReceiveThread extends Thread{ private LockBuffer buffer; public ReceiveThread(LockBuffer buffer){ this.buffer = buffer; } @Override public void run() { for(int i=1; i<=5; i++){ int num = buffer.get(); System.out.println("\t\t\t"+this.getClass().getName()+"get:"+num); } } } class Run{ public static void main(String[] args) { LockBuffer buffer = new LockBuffer(); (new SendThread(buffer)).start(); (new ReceiveThread(buffer)).start(); }<pre name="code" class="java">结果:可以与上面的对面,就可以看出有什么不同了
package p25.cooperate.co; import java.util.*; import java.awt.*; import javax.swing.*; public class CardJFrame extends JFrame { public CardJFrame() { super("发牌程序"); this.setSize(460,200); this.setLocation(300,240); this.setDefaultCloseOperation(EXIT_ON_CLOSE); Container container=this.getContentPane(); container.setLayout(new GridLayout(3,3)); //3行3列网格布局 container.add(new JPanel()); //网格布局的第1行第1列 JTextArea text[]=new JTextArea[4]; //显示牌号的4个文本区 Font font=new Font("Helvetica", Font.PLAIN, 16); for (int i=0; i<text.length; i++) { text[i]=new JTextArea(); text[i].setLineWrap(true); //设置文本区自动换行 text[i].setEditable(false); text[i].setFont(font); container.add(text[i]); container.add(new JPanel()); } this.setVisible(true); CardBuffer cardbuffer = new CardBuffer(); Sender s = new Sender(cardbuffer,52); s.setPriority(10); //设置最高优先级 s.start(); //启动发牌线程 for (int i=0; i<text.length; i++) (new Receiver(cardbuffer,text[i],i)).start(); //创建并启动4个取牌线程,优先级为5 } public static void main(String arg[]) { new CardJFrame(); } } class CardBuffer { private int value; private boolean isEmpty=true; //value是否空的信号量 private int order=0; //信号量,约定取牌线程的次序 synchronized void put(int i) { while (!isEmpty) //当value不空时,等待 try { this.wait(); //等待 } catch(InterruptedException e) {} value=i; //当value空时,value获得值 isEmpty=false; //设置value为不空状态 notifyAll(); //唤醒所有其他等待线程 } synchronized int get(int order) //order是取牌线程约定的次序 { while (isEmpty || (this.order!=order)) //当value空或取牌次序不符时等待 try { this.wait(); } catch(InterruptedException e) {} isEmpty=true; //设置value为空状态,并返回值 notifyAll(); this.order=(this.order+1)%4; //加1使取牌次序轮转 return value; } } /* class Sender extends Thread //发牌线程类 { private CardBuffer cardbuffer; private int count; //牌数 public Sender(CardBuffer cardbuffer,int count) { this.cardbuffer=cardbuffer; this.count=count; } public void run() { for (int i=1; i<=this.count; i++) cardbuffer.put(i); } }*/ class Receiver extends Thread //取牌线程类 { private CardBuffer cardbuffer; private JTextArea text; private int order; //信号量,约定取牌线程的次序 public Receiver(CardBuffer cardbuffer,JTextArea text,int order) { this.cardbuffer = cardbuffer ; this.text = text ; this.order = order; } public void run() { while(true) { text.append(" "+cardbuffer.get(this.order)); try { Thread.sleep(100); } catch(InterruptedException e) {} } } } //52 1-52 1-13黑 14-26红 27-39梅 40-52方 35%13 //a[52] 1-52 //for(int i=0;i<a.length;i++){ // a[i] <--> a[rand] //} class Sender extends Thread //发牌线程类 { private CardBuffer cardbuffer; private int count; //牌数 private java.util.ArrayList<Integer> list; //数组列表 public Sender(CardBuffer cardbuffer,int count) { this.cardbuffer=cardbuffer; this.count=count; list=new ArrayList<Integer>(); for (int i=1; i<=this.count; i++) list.add(new Integer(i)); //列表中添加整数对象 java.util.Random rand=new Random(); //随机数序列对象 java.util.Collections.shuffle(list, rand); //将列表的数据序列打散,按随机数序列 } public void run() { // for (int i=1; i<=this.count; i++) // cardbuffer.put(((Integer)list.get(i-1)).intValue()); //或 Iterator<Integer> it=list.iterator(); //返回一个迭代器对象 while (it.hasNext()) //若有后继元素,使用迭代器遍历一个集合 cardbuffer.put((Integer)it.next()); //返回后继元素 } }结果:
1、创建线程和启动线程并不相同:在一个线程对新线程的Thread对象调用start()方法之前,这个线程并没有真正开始执行。Thread对象在其
线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。因此,仍可以控制或获取关于已创建的线程的信息,即使线程还没有启动
或已经完成了。
2、结束线程:1)线程到达其run()方法的末尾,推荐这种方法,自然结束。
2)线程抛出一个未捕获到的Exception或Error。
3)另一个线程调用一个弃用的stop()方法。
3、守护程序线程(简称守护线程):我们提到过当Java程序的所有线程都完成时,该程序就退出,但这并不完全正确,因为程序中还隐藏的
系统线程。
1、synchronized必须锁的是对象,基本数据类型的变量不能当作对象锁。
2、要保证多线程使用的是同一个互斥锁(对象锁),才能进行同步。
3、死锁的两种情况:1)多个线程共用同一个对象锁,互相等待。
2)互相持有对方所需的资源(即每个线程都需要同时拿到多个资源才能继续执行,而多个线程都处于:各持有一部分,在等待另一部分。)
4、死锁的解决:要从设计方面去解决避免,即在设计时就考虑不能出现死锁。罗列出所有临界资源,画分布图,从图中观察其中的死锁情
况,改变其中线程的(临界)资源的获取方式。设计原则:尽量让程序中少出现临界资源。
5、wait/notify 和 sleep方法:wait和notify只能在它们被调用的实例的同步块内使用,而sleep()到处都可以用。wait()和sleep()最大的区别:
sleep()不释放对象锁,而wait()会释放,因此从效率方面考虑wait()方法更好。
6、 同步设计的基本原则: ◎ 同步块中(synchronized修饰)的代码越小越好!
◎ 同步块中不要写阻塞性代码(如,InputStream.read() )!
◎ 在持有锁的时候,不要对其它对象调用方法。(如果做到,可以消除最常见的死锁源头。)
7、同步概述:◎同步的原理:将需要同步的代码进行封装,并在该代码上加了一个锁。
◎同步的好处:解决多线程的安全问题。
◎同步的弊端:会降低性能。
◎同步的前提:必须要保证有多个线程且它们在同步中使用的是同一个锁。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u011479875/article/details/47345033