略……
public class Test {
public static void main(String[] args) {
// 执行多线程
MyThread thread = new MyThread();
thread.start();
// 执行主线程
for (int i = 0; i < 500; i++) {
System.out.println("我在执行主线程...");
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("我在执行多线程...");
}
}
}
public class Test {
public static void main(String[] args) {
// 执行多线程
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
// 执行主线程
for (int i = 0; i < 500; i++) {
System.out.println("我在执行主线程...");
}
}
}
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("我在执行多线程...");
}
}
}
public class TestJoin {
public static void main(String[] args) {
MyThread2 t1 = new MyThread2("线程t1");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
System.out.println("我是主线程");
}
}
}
class MyThread2 extends Thread {
MyThread2(String s) {
super(s);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我是" + getName());
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test {
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);
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + ": " + i);
// 逢10的倍数,让给另一个线程执行
// 可能因为计算机的性能问题有些不准确
if (i % 10 == 0){
yield();
}
}
}
}
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
t1.setPriority(Thread.NORM_PRIORITY + 3); // 将t1的默认优先级5提高3
t1.start();
t2.start();
}
}
class T1 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("T1: " + i);
}
}
}
class T2 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("-----T2: " + i);
}
}
}
先看以下的测试用例:
public class Test implements Runnable{
Timer timer = new Timer();
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public void add(String name) {
num ++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ",你是第" + num + "个使用timer的线程");
}
}
我们预期是希望输出:
t1,你是第1个使用timer的线程
t2,你是第2个使用timer的线程
可是运行的结果却是:
原因在于线程t1执行对num增至1时,CPU可能去执行线程t2,使得此时num增至2,那么线程t1再次执行时,就有可能输出2(注意:我这里使用了sleep,是为了增强效果,确保t1 在执行的过程中被t2给打断,即便不使用sleep,线程t1也有可能会输出“第二个使用timer的线程”)
所以,我们可以使用synchronized关键字对其加锁
public class Test implements Runnable{
Timer timer = new Timer();
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public synchronized void add(String name) {
num ++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ",你是第" + num + "个使用timer的线程");
}
}
使用了synchronized,在执行方法时就会锁定当前对象(在执行这个方法时,当前对象被锁定),如果另一个对象也想使用这个方法,只能等待!
public class Test implements Runnable{
public int flag = 1;
static Object obj1 = new Object(), obj2 = new Object();
@Override
public void run() {
System.out.println("flag=" + flag);
if (flag == 1) { // obj1的线程从此处进入
synchronized (obj1) { // 锁住obj1
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) { // 只要再能锁住obj2,就打印 1
System.out.println("1");
}
}
}
if (flag == 0) { // obj2的线程从此处进入
synchronized (obj2) { // 锁住obj2
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) { // 只要再能锁住obj1,就打印 0
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
test1.flag = 1;
test2.flag = 0;
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
}
}
可以看到,程序在打印了下面两行后,便锁住了无法继续执行下去,原因就是当obj1线程执行了锁住自己的操作后,睡眠了0.5秒,此时obj2执行锁住自己操作;那么之后两个线程就进入了死锁状态,无法继续执行~(一开始也有可能是obj2先执行锁住自身操作)
public class Test implements Runnable{
int b = 100;
public synchronized void m1() throws InterruptedException {
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
public void m2() {
System.out.println(b);
}
@Override
public void run() {
try {
m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t = new Thread(test);
t.start();
Thread.sleep(1000);
test.m2();
}
}
运行结果:
说明synchronized只是锁住了当前的方法,而另一个线程完全可以访问其他的方法,所以第一个输出的是1000,而不是100
即synchronized只能保证在同一时间,只能有一个线程访问这个被锁住的方法,但是无法影响另一个线程能否执行
public class Test implements Runnable{
int b = 100;
public synchronized void m1() throws InterruptedException {
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
public void m2() throws InterruptedException {
System.out.println(b);
Thread.sleep(2500);
b = 2000;
}
@Override
public void run() {
try {
m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t = new Thread(test);
t.start();
test.m2(); // 方法调用
}
}
运行结果:
从结果看出最后输出的是2000,而不是1000;同样说明了synchronized的特性,另一方面看出b是一种资源,凡是需要访问b这个资源的方法都必须要考虑同步锁的问题,否则会产生冲突,得到错误的结果
如果为 m2 方法也加上synchronized,输出结果如下:
100
b = 1000
两个方法都加锁的情况下,只有当一个方法不再为锁住状态时,另一个方法才能执行。
注意使用while循环而不是if判断的点
当醒来的一瞬间可能栈又满了,所以while判断更保险
wait: Object类的方法,wait的时候,会放开这把锁
sleep: Thread类的方法,sleep的时候,并不会放开锁
notify/notifyAll: 把正在等待的线程唤醒,这是必须的操作,不同于sleep会自己醒来
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;
public Wotou(int id) {
this.id = id;
}
@Override
public String toString() {
return "Wotou{" +
"id=" + id +
'}';
}
}
class SyncStack {
int index = 0;
Wotou[] arrWT = new Wotou[6];
public synchronized void push(Wotou wt) {
while (index == arrWT.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); // 叫醒一个正在当前对象等待的线程
arrWT[index] = wt;
index ++;
}
public synchronized Wotou pop() {
while (index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index --;
return arrWT[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
public Producer(SyncStack ss) {
this.ss = ss;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
Wotou wt = new Wotou(i);
ss.push(wt);
System.out.println("生产了:" + wt);
try {
Thread.sleep((int) (Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
public Consumer(SyncStack ss) {
this.ss = ss;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
Wotou wt = ss.pop();
System.out.println("消费了" + wt);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}