Java之多线程机制-(2)

来源:互联网 发布:德里克罗斯体测数据 编辑:程序博客网 时间:2024/05/16 15:07

线程同步:若干个线程都需要使用一个synchronized(同步)修饰的方法,即程序中的若干个线程都需要使用一个方法,而这个方法用synchronized给予了修饰。

线程同步机制:当一个线程A使用synchronized方法时,其他线程想使用这个synchronized方法时就必须等待,直到线程A使用完该synchronized方法。

class Bank implements Runnable{int money = 200;Thread accountant;Thread cashier;public void setMoney(int n){money = n;}Bank(){accountant = new Thread(this);cashier = new Thread(this);accountant.setName("会计");cashier.setName("出纳");}public void run(){if(Thread.currentThread()==accountant){saveOrTake(300);}else{saveOrTake(150);}}public synchronized void saveOrTake(int amount){  //synchronized方法if(Thread.currentThread()==accountant){for(int i=0; i<3; i++){money += amount/3;System.out.println(Thread.currentThread().getName()+"存入"+amount/3+",账上有"+money);try{Thread.sleep(1000);}catch(InterruptedException e){}}}else{for(int i=0; i<3; i++){money -= amount/3;System.out.println(Thread.currentThread().getName()+"取出"+amount/3+",账上有"+money);try{Thread.sleep(1000);}catch(InterruptedException e){}}}}}public class E{public static void main(String args[]){Bank bank = new Bank();bank.accountant.start();bank.cashier.start();}}

协调同步的线程:

当一个线程使用的同步方法中用到某个变量,而此变量又需要其他线程修改后才能符合本线程的需要,那么可以在同步方法中使用wait()方法。wait方法可以中断线程的执行,使本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步的方法。其他线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方法的同时,应当使用notifyAll()方法通知所有由于使用这个同步方法而处于等待的线程结束等待,曾中断的线程就会从刚才的中断处继续执行这个同步方法,并遵循“先中断先继续”的原则。如果使用notify()方法,那么只是通知处于等待中的线程的某一个结束等待。
注意:wait(), notify(), notifyAll(),都是object类中的final方法,被所有的类继承并不允许重写。不可以在非同步方法中使用上述方法。
在许多实际问题中,wait方法应当放在一个while(等待条件){}的循环语句中,而不是if(等待条件){}的分支语句中。
class TicketHouse implements Runnable{int fiveAmount = 2, tenAmount = 0, twentyAmount = 0;public void run(){if(Thread.currentThread().getName().equals("张飞"))saleTicket(20);else if(Thread.currentThread().getName().equals("李逵"))saleTicket(5);}private synchronized void saleTicket(int money){if(money==5){fiveAmount++;System.out.println("给"+Thread.currentThread().getName()+"入场券,"+Thread.currentThread().getName()+"的钱正好");}else if(money==20){while(fiveAmount<3){try{System.out.println("\n"+Thread.currentThread().getName()+"靠边等...");wait(); System.out.println("\n"+Thread.currentThread().getName()+"继续买票");}catch(InterruptedException e){}}fiveAmount -= 3;twentyAmount++;System.out.println("给"+Thread.currentThread().getName()+"入场券,"+Thread.currentThread().getName()+"给20, 找15元");}notifyAll();}}public class E{public static void main(String args[]){TicketHouse officer = new TicketHouse();Thread zhangfei, likui;zhangfei = new Thread(officer);zhangfei.setName("张飞");likui = new Thread(officer);likui.setName("李逵");zhangfei.start();likui.start();}}

线程联合:

如果线程A在占有CPU资源期间一旦联合B线程,那么A线程将立刻中断执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源,以便恢复执行。如果A准备联合的B线程已经结束,那么B.join()不会产生任何效果。

class ThreadJoin implements Runnable{Cake cake;Thread joinThread;public void setJoinThread(Thread t){joinThread = t;}public void run(){if(Thread.currentThread().getName().equals("顾客")){System.out.println(Thread.currentThread().getName()+"等待"+joinThread.getName()+"制作生日蛋糕");try{joinThread.start();   //唯有顾客需要时,才执行start()joinThread.join();   //当前线程开始并等待joinThread结束}catch(InterruptedException e){}System.out.println(Thread.currentThread().getName()+"买了"+cake.name+"价钱:"+cake.price);}else if(Thread.currentThread()==joinThread){System.out.println(joinThread.getName()+"开始制作生日蛋糕,请稍等");try{Thread.sleep(3000);}catch(InterruptedException e){}cake = new Cake("生日蛋糕", 158);System.out.println(joinThread.getName()+"制作完毕");}}class Cake{              //内部类int price;String name;Cake(String name, int price){this.price = price;this.name = name;}}}public class E{public static void main(String args[]){ThreadJoin a = new ThreadJoin();Thread customer = new Thread(a);Thread cakeMaker = new Thread(a);customer.setName("顾客");cakeMaker.setName("蛋糕师");a.setJoinThread(cakeMaker);customer.start();}}

GUI线程:

AWT-EventQueue线程:负责处理GUI事件
AWT-Windows线程:负责将窗体或组件绘制到桌面

import java.awt.*;import java.awt.event.*;import javax.swing.*;class GameWindow extends JFrame implements ActionListener, Runnable{JTextField inputLetter;JLabel showLetter, showScore;Thread giveLetter;int sleepTime=3000, score;GameWindow(){setTitle("打字母游戏");setLayout(new FlowLayout());inputLetter = new JTextField(6);showLetter = new JLabel(" ", JLabel.CENTER);showLetter.setFont(new Font("Arial", Font.BOLD, 22));showScore = new JLabel("分数:");add(new JLabel("显示字母:"));add(showLetter);add(new JLabel("输入所显示的字母"));add(inputLetter);add(showScore);inputLetter.addActionListener(this);setBounds(100, 100, 400, 280);setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);giveLetter = new Thread(this);giveLetter.start();}public void run(){char c = 'a';while(true){showLetter.setText(""+c+" ");validate();c = (char)(c+1);if(c>'z')c = 'a';try{Thread.sleep(sleepTime);}catch(InterruptedException e){}}}public void actionPerformed(ActionEvent e){String s = showLetter.getText().trim();String letter = inputLetter.getText().trim();if(s.equals(letter)){score++;showScore.setText("得分"+score);inputLetter.setText(null);validate();giveLetter.interrupt();}}}public class E{public static void main(String args[]){GameWindow gw = new GameWindow();}}

计时器线程: 

在javax.swing包中,有一个Timer类。构造方法:Timer(int a, Object b), a的单位为毫秒,计时器每隔a毫秒“振铃”一次,b为这个计时器的监视器。负责创建监视器的类必须实现接口ActionListener,计时器的监视器必须是组件类(JFram, JButton等)的子类的实例。
计时器方法:start()启动计时器,即启动线程。
stop()停止计时器
restart()重新启动计时器
import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;import java.awt.*;import java.util.Date;import java.text.*;public class WindowTime extends JFrame implements ActionListener{JTextField text;JButton bStart, bStop, bContinue;Timer time;SimpleDateFormat m;int n=0, start = 1;WindowTime(){time = new Timer(1000, this);m = new SimpleDateFormat("hh:mm:ss");text = new JTextField(10);bStart = new JButton("开始");bStop = new JButton("停止");bContinue = new JButton("继续");bStart.addActionListener(this);bStop.addActionListener(this);bContinue.addActionListener(this);setLayout(new FlowLayout());add(bStart);add(bStop);add(bContinue);add(text);setSize(500, 500);validate();setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubif(e.getSource()==time){Date date = new Date();text.setText("时间:"+m.format(date));int x = text.getBounds().x;int y = text.getBounds().y;y += 2;x -= 2;text.setLocation(x, y);}else if(e.getSource()==bStart){time.start();}else if(e.getSource()==bStop){time.stop();}else if(e.getSource()==bContinue){time.restart();}}}

守护线程:

线程默认是非守护线程(用户线程),一个线程调用void setDaemon(boolean on)可以将自己设置成一个守护线程。当程序中的所有用户线程都已结束运行时,即使守护线程的run方法中还有需要执行的语句守护线程也会立刻结束运行。我们可以用守护线程做一些不是很严格的工作,线程的随时结束不会产生什么不良的后果。一个线程必须在运行之前设置自己是否是守护线程。


0 0
原创粉丝点击