多线程 生产者&消费者 哲学家进餐 & random & synchronized & Thread & Sleep
2015-10-31 22:42
357 查看
基础知识点
sleep()不会放开锁,而wait()会放开锁,让其他的进程执行两种实现方法
public class TestThread1 { public static void main(String args[]) { Runner1 r = new Runner1(); r.start(); //r.run(); //Thread t = new Thread(r); //t.start(); for(int i=0; i<100; i++) { System.out.println("Main Thread:------" + i); } } } //class Runner1 implements Runnable { class Runner1 extends Thread { public void run() { for(int i=0; i<100; i++) { System.out.println("Runner1 :" + i); } } }
测试 yield
短暂的sleep,给其他进程让出一点时间public class TestYield { public static void main(String[] args) { MyThread3 t1 = new MyThread3("t1"); MyThread3 t2 = new MyThread3("t2"); t1.start(); t2.start(); } } class MyThread3 extends Thread { MyThread3(String s) { super(s); } public void run() { for (int i = 1; i <= 100; i++) { System.out.println(getName() + ": " + i); if (i % 10 == 0) { yield(); } } } }
测试 synchronized
观察b的输出结果,看synchronized 是否影响b 的访问一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞.
五、以上规则对其它对象锁同样适用.
public class TT implements Runnable { int b = 100; public synchronized void m1() throws Exception{ //Thread.sleep(2000); b = 1000; Thread.sleep(5000); System.out.println("b = " + b); } // public synchronized void m2() throws Exception { public void m2() throws Exception { Thread.sleep(2500); b = 2000; } public void run() { try { m1(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { TT tt = new TT(); Thread t = new Thread(tt); t.start(); tt.m2(); System.out.println(tt.b); } }
java 中 volatile 关键字
volatile的主要作用是:提示编译器该对象的值有可能在编译器未监测的情况下被改变。如果一个基本变量被volatile修饰,编译器将不会把它保存到寄存器中,而是每一次都去访问内存中实际保存该变量的位置上。这一点就避免了没有volatile修饰的变量在多线程的读写中所产生的由于编译器优化所导致的灾难性问题。所以多线程中必须要共享的基本变量一定要加上volatile修饰符。当然了,volatile还能让你在编译时期捕捉到非线程安全的代码。
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式。
下面例子运行结果还是没有我们期望的1000,原因见
/article/4878212.html
public class Counter { public volatile static int count = 0; public static void inc() { //这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) { } count++; } public static void main(String[] args) { //同时启动1000个线程,去进行i++计算,看看实际结果 for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { Counter.inc(); } }).start(); } //这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:Counter.count=" + Counter.count); } }
经典死锁例子
public class TestDeadLock implements Runnable { public int flag = 1; static Object o1 = new Object(), o2 = new Object(); public void run() { System.out.println("flag=" + flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { System.out.println("0"); } } } } public static void main(String[] args) { TestDeadLock td1 = new TestDeadLock(); TestDeadLock td2 = new TestDeadLock(); td1.flag = 1; td2.flag = 0; Thread t1 = new Thread(td1); Thread t2 = new Thread(td2); t1.start(); t2.start(); } }
生产者和消费者
涉及到的小知识点
利用URL加载图片解决第一次图片加载不成功
同一类中的方法加synchronized 锁
ProducerConsumer.java
类的粒度太小一个java文件就够了可以直接运行的
提供了图形界面和非图形界面两种版本
参考soldier线程中的例子
/* 范例名称:生产者--消费者问题 * 源文件名称:ProducerConsumer.java * 要 点: * 1. 共享数据的不一致性/临界资源的保护 * 2. Java对象锁的概念 * 3. synchronized关键字/wait()及notify()方法 */ public class ProducerConsumer { public static void main(String[] args) { SyncStack ss = new SyncStack(); Producer p = new Producer(ss); Consumer c = new Consumer(ss); new Thread(p).start(); // new Thread(p).start(); // new Thread(p).start(); new Thread(c).start(); } } class WoTou { int id; WoTou(int id) { this.id = id; } public String toString() { return "WoTou : " + id; } } class SyncStack { int index = 0; WoTou[] arrWT = new WoTou[3]; public synchronized void push(WoTou wt) { while(index == arrWT.length) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll(); arrWT[index] = wt; index ++; } public synchronized WoTou pop() { while(index == 0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll(); index--; return arrWT[index]; } } class Producer implements Runnable { public static int len1 = 0;//留给图形化界面用 SyncStack ss = null; Producer(SyncStack ss) { this.ss = ss; } public void run() { for(int i=0; i<100; i++) { WoTou wt = new WoTou(i); ss.push(wt); len1 += 1; if(len1 > 100) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("len1 = " + len1); System.out.println("生产了: " + wt); try { Thread.sleep((int)(Math.random() * 200)); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable { public static int len2 = 0;//留给图形化界面用 SyncStack ss = null; Consumer(SyncStack ss) { this.ss = ss; } public void run() { for(int i=0; i<100; i++) { WoTou wt = ss.pop(); len2 += 1; if(len2 > 100) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("len2 = " + len2); System.out.println("消费了: " + wt); try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
MainFrame.java
在src的同级目录下建立images文件夹命名图片0.jpg, 1.jpg
这里会解决一下坦克第一次爆照不出图片的问题
使用的是URL定位图片资源的
出自操作系统上机实验的作业
参考soldier坦克大战图片版
是上面的ProducerConsumer.java的图片版,要放在一起使用,使用时注释掉ProducerConsumer.java中那几个syso输出语句
ProducerConsumer.java也可以单独使用
import java.awt.*; import java.awt.event.*; public class MainFrame extends Frame{ private static Toolkit tk = Toolkit.getDefaultToolkit(); private static boolean init = false; SyncStack ss; Producer p; Consumer c; private static Image[] imgs = { tk.getImage(MainFrame.class.getClassLoader().getResource("images/0.jpg")), tk.getImage(MainFrame.class.getClassLoader().getResource("images/1.jpg")), }; public static final int REC_WIDTH = 600; public static final int REC_HEIGH = 15; public static final int REC1_X = 100; public static final int REC1_Y = 300; public static final int REC2_X = 100; public static final int REC2_Y = 500; BloodBar bar1 = new BloodBar(REC1_X, REC1_Y, REC_WIDTH, REC_HEIGH, 0); BloodBar bar2 = new BloodBar(REC2_X, REC2_Y, REC_WIDTH, REC_HEIGH, 1); public void paint(Graphics g) { bar1.draw(g); bar2.draw(g); } public void launchFrame() { setLocation(100, 100); setSize(800, 600); setResizable(false); setBackground(Color.green); setTitle("Police_Thief"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); addKeyListener(new KeyMonitor()); setVisible(true); new Thread(new PaintThread()).start(); } public static void main(String[] args) { new MainFrame().launchFrame(); } private class KeyMonitor extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if(key == KeyEvent.VK_CONTROL) { ss = new SyncStack(); p = new Producer(ss); c = new Consumer(ss); new Thread(p).start(); new Thread(c).start(); } } } private class PaintThread implements Runnable { public void run() { while(true) {//这里注意一下 repaint(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } private class BloodBar {//画警察和小偷血条的类 int x, y, width, heigh, id; public BloodBar(int x, int y, int width, int heigh, int id) { this.x = x; this.y = y; this.width = width; this.heigh = heigh; this.id = id; } public void draw(Graphics g) { if(!init) {//这样做是为了解决2.8_2第一次花爆炸画不出来 for (int i = 0; i < imgs.length; i++) { g.drawImage(imgs[i], -100, -100, null); } init = true; } Color color = g.getColor(); g.setColor(Color.RED); g.drawRect(x, y, width, heigh); int w; if(id == 0) w = p.len1; else w = c.len2; int ww = w * (REC_WIDTH / 100);//将血条的长度设置成100 g.fillRect(x, y, ww, heigh); g.setColor(color); g.drawImage(imgs[id], x + ww, y - 100, null); g.drawString(w + "", x + ww, y + 30); } } }
哲学家进餐
涉及到的小知识点
进程等待任意时间建立ChopstickArray来管理Chopsticks
DiningPhilosophersFrame.java
操作系统上机实验作业这是swing版本的
Frame版本的在我的网盘里,由于代码大部分类似,没有贴出来
public class DiningPhilosophersFrame extends JFrame { private final JPanel panel1 = new JPanel(); private final JPanel panel2 = new JPanel(); private final JTextArea thinkingTextArea = new JTextArea(5, 10); private final JTextArea eatingTextArea = new JTextArea(5, 10); private final JTextArea waitingTextArea = new JTextArea(5, 10); JLabel label1 = new JLabel("哲学家问题"); JLabel label2 = new JLabel("思考"); JLabel label3 = new JLabel("吃饭"); JLabel label4 = new JLabel("等待"); JButton button = new JButton("开始运行"); public DiningPhilosophersFrame() { panel2.setLayout(new GridLayout(2, 2, 3, 3)); panel2.add(label2); panel2.add(label3); panel2.add(label4); JScrollPane js1 = new JScrollPane(thinkingTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); JScrollPane js2 = new JScrollPane(eatingTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); JScrollPane js3 = new JScrollPane(waitingTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); panel2.add(js1); panel2.add(js2); panel2.add(js3); panel1.setLayout(new FlowLayout()); panel1.add(label1); panel1.add(panel2); panel1.add(button); setContentPane(panel1); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ChopstickArray chopstickArray = new ChopstickArray(5); for (int i = 0; i < 5; i++) { new Thread(new Philosopher(i, chopstickArray, thinkingTextArea, eatingTextArea, waitingTextArea)) .start(); } } }); setSize(300, 400); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new DiningPhilosophersFrame(); } }
Philosopher.java
public class Philosopher implements Runnable { private int id; private boolean state; //false停止思考,寻找筷子 true在思考 ChopstickArray chopstickArray; JTextArea thinkingTextArea; JTextArea eatingTextArea; JTextArea waitingTextArea; public Philosopher(int id, ChopstickArray chopstickArray, JTextArea thinkingTextArea, JTextArea eatingtextArea, JTextArea waitingTextArea) { this.id = id; this.chopstickArray = chopstickArray; this.thinkingTextArea = thinkingTextArea; this.eatingTextArea = eatingtextArea; this.waitingTextArea = waitingTextArea; } public synchronized void thinking() { if (state) { // 如果在思考,说明这个哲学家两面的筷子没用 chopstickArray.getById(id).setAvailable(true); chopstickArray.getLast(id).setAvailable(true); String text = thinkingTextArea.getText(); thinkingTextArea.setText(text + this + "在思考\n"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } state = false;//开始找筷子 } public synchronized void eating() { if (!state) { // 开始找筷子 if (chopstickArray.getById(id).isAvailable()) { // 如果哲学家右手边的筷子可用 if (chopstickArray.getLast(id).isAvailable()) { // 如果左手边的筷子也可用 // 然后将这个能吃饭的哲学家两侧的筷子都设置为不可用 chopstickArray.getById(id).setAvailable(false); chopstickArray.getLast(id).setAvailable(false); String text = eatingTextArea.getText(); eatingTextArea.setText(text + this + "在吃饭\n"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } else { // 右手边的筷子可用,但是左手边的不可用 String str = waitingTextArea.getText(); waitingTextArea.setText(str + this + "在等待" + chopstickArray.getLast(id) + "\n"); try { wait(new Random().nextInt(100)); } catch (Exception e) { e.printStackTrace(); } } } else { // 如果哲学家右手边的筷子不可用则等待 String str = waitingTextArea.getText(); waitingTextArea.setText(str + this + "在等待" + chopstickArray.getById(id) + "\n"); try { wait(new Random().nextInt(100)); } catch (Exception e) { e.printStackTrace(); } } } state = true; } @Override public void run() { for (int i = 0; i < 10; ++i) { thinking(); eating(); } } @Override public String toString() { return " 哲学家 " + id; } }
ChopstickArray.java
public class ChopstickArray { private Chopstick[] chopsticks; public ChopstickArray(int size) { chopsticks = new Chopstick[size]; for (int i = 0; i < chopsticks.length; ++i) { chopsticks[i] = new Chopstick(i); } } public Chopstick getById(int id) { return chopsticks[id]; } public Chopstick getLast(int id) { if (id == 0) { return chopsticks[chopsticks.length - 1]; } else { return chopsticks[id - 1]; } } }
Chopstick.java
public class Chopstick { private volatile boolean available = true; private int id; public Chopstick(int id) { this.id = id; } public boolean isAvailable() { return available; } public void setAvailable(boolean available) { this.available = available; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "筷子" + id; } }
相关文章推荐
- 数据库范式
- 2015.10.31
- 整除快速判断
- Techparty-广州 10 月 31 日 Docker 专场沙龙 后记
- CCNA——交换机
- HDU 3861 The King’s Problem(强连通缩点 + 最小路径覆盖)
- 动态规划之 0-1背包问题及改进
- 数据库触发器
- 统计字符串中:各个数字、空白字符、以及其他所有字符出现的次数
- Idea配置svn
- Java Integer问题
- Android内存优化(4)
- 用 WinPcap 获取网络接口列表
- nyoj 众数问题 95 (数学)
- WebP 探寻之路 --- SDWebImage支持webp格式的图片
- emacs echo area 不是行缓冲的
- 数据库查询
- Android发送短信验证码
- C与Python变量的区别
- 3D数学 欧拉角类源代码(附中文注释)