基础知识点
- sleep()不会放开锁,而wait()会放开锁,让其他的进程执行
两种实现方法
public class TestThread1 {
public static void main(String args[]) {
Runner1 r = new Runner1();
r.start();
for(int i=0; i<100; i++) {
System.out.println("Main Thread:------" + i);
}
}
}
class Runner1 extends Thread {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("Runner1 :" + i);
}
}
}
测试 yield
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{
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
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,原因见
- http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
public class Counter {
public volatile static int count = 0;
public static void inc() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
count++;
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
}
}).start();
}
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线程中的例子
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(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) {
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);
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;
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;
}
}