目录
目录
写在最前:
可能有误,请大家批评指正
一、线程切换
Java中,如果要实现在一个线程间的线程切换,需要在线程中使用Thread.yield()即可让出CPU时间。
二、线程锁(也叫同步锁、互斥锁)
线程锁可以在有效缩小同步范围的同时,尽可能的保证并发效率
2.1 使用synchronized关键字对方法进行加锁
对整个线程处理加锁(严重影响效率,不常用)
2.1.1 语法
public synchronized void test(){
}
2.1.2 案例
package com.javase.thread;
import javax.management.RuntimeErrorException;
/**
* 这个类主要讲了Sychronized关键字,给方法加了Synchronized关键字以后,线程在调用这个方法时,相当于对这个方法加了锁,
* 那么其他线程就不能调用这个方法了(处于阻塞状态)
*
* @author gupan
*
*/
public class ThreadSyncSychronized {
public static void main(String[] args) {
final Table2 table = new Table2();
Thread t1 = new Thread() {
public void run() {
while (true) {
try {
int bean = table.getBean();
Thread.yield(); // 线程切换语句,让出CPU时间
System.out.println(getName() + "," + table.getBean());
} catch (RuntimeErrorException e) {
System.out.println(getName() + "," + e);
break;
}
}
}
};
Thread t2 = new Thread() {
public void run() {
while (true) {
try {
int bean = table.getBean();
Thread.yield(); // 线程切换语句,让出CPU时间
System.out.println(getName() + "," + table.getBean());
} catch (RuntimeErrorException e) {
System.out.println(getName() + "," + e);
break;
}
}
}
};
t2.start();
t1.start();
}
}
class Table2{
// 桌子上有20元钱
private int beans = 20;
public synchronized int getBean() throws RuntimeErrorException{
if (this.beans == 1) {
throw new RuntimeErrorException(null, "地主家没有余粮了");
}
Thread.yield(); // 线程切换语句,让出CPU时间
return this.beans--;
}
}
2.2 使用synchronize关键字对线程方法中的某一部分加锁(同步块的方式)
2.2.1 语法
// 注意这里是this,可以写new Object(),但是这样起不到加锁的效果
// 也就是说,要实现加锁的效果,需要保证是对同一个对象(也就是保证synchronized后面所跟对象是同一个)加锁
synchronized(this){
···
// 加锁语句
}
2.2.2 案例
package com.javase.thread;
/**
* 这个类主要演示小范围的使用锁。尽可能的提高并发效率
*
* synchronized(this){
* ···
* // 加锁语句
* }
*
* @author Think
*
*/
public class ThreadSyncLock {
public static void main(String[] args) {
final Shop shop = new Shop();
Thread t1 = new Thread() {
public void run() {
shop.buy();
}
};
Thread t2 = new Thread() {
public void run() {
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
public void buy() {
Thread t = Thread.currentThread();
try {
System.out.println(t.getName() + "正在挑衣服");
Thread.sleep(1000);
// 需要传入当前方法所属对象,所以这里要传入this
synchronized (this) {
System.out.println(t.getName() + "正在试衣服");
Thread.sleep(1000);
}
System.out.println(t.getName() + "结账离开");
Thread.sleep(1000);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
2.3 静态方法加锁
如果对静态方法加了synchronized关键字,由于静态方法只有一份,整个方法一定是加了互斥锁
package com.javase.thread;
import com.javase.string.Object;
/**
* 静态方法的同步
* 当一个静态方法被synchronized修饰以后,那么该方法就是同步方法,由于静态方法从属类,
* 全局就一份,所以同步的静态方法一定具有同步效果,与对象无关
*
* @author gupan
*
*/
public class ThreadSyncStatic {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
Foo.dosome();
}
};
Thread t2 = new Thread() {
public void run() {
Foo.dosome();
}
};
t1.start();
t2.start();
}
}
class Foo{
public static synchronized void dosome() {
try {
Thread t = Thread.currentThread();
System.out.println(t.getName() + "正在等待运行dosome方法");
Thread.sleep(1000);
System.out.println(t.getName() + "正在运行dosome方法");
Thread.sleep(1000);
System.out.println(t.getName() + "执行dosome方法完毕");
}catch (Exception e) {
// TODO: handle exception
}
}
}
运行结果:
Thread-1正在等待运行dosome方法
Thread-1正在运行dosome方法
Thread-1执行dosome方法完毕
Thread-0正在等待运行dosome方法
Thread-0正在运行dosome方法
Thread-0执行dosome方法完毕
2.3 互斥锁
2.3.1 同步锁和互斥锁
同步锁和互斥锁原理相同,存在的是用法上的小差异。当两个线程调用同一段代码,并且,对于两个线程的同步监视器,看到的代码相同,那就是同步锁;但是,对于几段代码,用一个同步监视器进行访问,几段代码不能同时执行,就是互斥锁
package com.javase.thread;
/**
* 这段代码主要演示互斥锁的使用
* 使用synchronized修饰这段代码之后,只要他们同步监视器对象相同,那么这几段代码见就是互斥关系,多个线程不能同时执行这些代码
*
* @author gupan
*
*/
public class ThreadSyncMatual {
/**
* 线程t1和t2不能同时调用methodA或methodB方法,实现互斥关系
*
* @param args
*/
public static void main(String[] args) {
Boo boo = new Boo();
Thread t1 = new Thread() {
public void run() {
boo.methodA();
}
};
Thread t2 = new Thread() {
public void run() {
boo.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public void methodA(){
try{
Thread t = Thread.currentThread();
System.out.println(t.getName() + "正在执行A方法");
Thread.sleep(1000);
System.out.println(t.getName() + "执行A方法完毕");
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void methodB(){
try{
Thread t = Thread.currentThread();
System.out.println(t.getName() + "正在执行B方法");
Thread.sleep(1000);
System.out.println(t.getName() + "执行B方法完毕");
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}