- Runnable 和 Thread run() 都重写,执行Thread的run()
/**
* 创建新线程时,即重写父类run方法,亦实现Runnable参数的run方法
* 执行的是子类中重写的run方法,不是Runnable的run方法
* @author guchunchao
*
*/
public class TestThread {
public static void main(String[] args) {
System.out.println("main thread");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Runnable's method() instance");
}
}) {
public void run() {
System.out.println("Thread's method() override");
};
}.start();
}
}
- 多线程共调非synchronized的打印方法,打印出纰漏
public class TestSynchronized {
public static void main(String[] args) {
TestSynchronized obj = new TestSynchronized();
obj.init();
}
private void init() {
OutPut out = new OutPut();
new Thread() {
@Override
public void run() {
while(true)
out.print("hello world");
};
}.start();
new Thread() {
@Override
public void run() {
while(true)
out.print("guchunchaoxixihaha");
};
}.start();
}
class OutPut {
public void print(String str) {
for(int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i));
}
System.out.println();
}
}
}
错误结果:
guchunchaoxixihaha
guchunchaoxixiha
hello worha
guchunchaoxixihaha
guchunchaoxld
hello world
解决办法:在方法上➕synchronized关键字
面试题:
1.【子线程循环执行10次,主线程循环执行100次】50次
下面代码不加synchronized (MainSubThread.class) {}时输出语句交替执行,毫无章法可言,加上后则 synchronized包含的内部代码 for(10次 / 100次) 作为一个整体是连贯输出的,只有外面的主线程50次和子线程50次可能是交替的。
public class MainSubThread {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
//子线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
synchronized (MainSubThread.class) {
for (int j = 0; j < 10; j++) {
System.out.println("sub Thread run sequece of " + j + " loop of " + i);
}
}
}
}
}).start();
//主线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
synchronized (MainSubThread.class) {
for (int j = 0; j < 10; j++) {
System.out.println("main Thread run sequece of " + j + " loop of " + i);
}
}
}
}
}
- 面向对象方式封装重写版本
public class MainSubThread {
public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
@Override
public void run() {
//子线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
business.sub(i);
}
}
}).start();
//主线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
business.main(i);
}
}
}
class Business {
public synchronized void main(int i) {
for (int j = 0; j < 10; j++)
System.out.println("main Thread run sequece of " + j + " loop of " + i);
}
public synchronized void sub(int i) {
for (int j = 0; j < 10; j++)
System.out.println("sub Thread run sequece of " + j + " loop of " + i);
}
}
- 交替执行版本(wait notify):
public class MainSubThread {
public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
@Override
public void run() {
//子线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
business.sub(i);
}
}
}).start();
//主线程循环调用50次某逻辑
for(int i = 0; i < 50; i++) {
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
public synchronized void sub(int i) {
if(!bShouldSub) { //while 更健壮,根据API,可以防止伪唤醒
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 0; j < 10; j++)
System.out.println("sub Thread run sequece of " + j + " loop of " + i);
bShouldSub = false;
this.notify();
}
public synchronized void main(int i) {
if(bShouldSub) {//while 更健壮,根据API,可以防止伪唤醒
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 0; j < 10; j++)
System.out.println("main Thread run sequece of " + j + " loop of " + i);
bShouldSub = true;
this.notify();
}
}
wait()
在等待Condition吋,允许发生 “虚假唤醒” 这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态说明。某个实现可以随意移除可能的 “虚假唤醒” ,但建议应用程序员总是假定这些 “虚假唤醒” 可能发生,因此总是在一个循环中等
伪唤醒,为什么判断用while不用if
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。2个线程要执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。锁是尚在代表要操作的资源的类的内部方法中,而不是线程代码中
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写🔐互斥,写🔐与写🔐互斥,这是由jvm自己控制的,你只要上好相应的🔐即可。如果你的代码只读取数据,可以很多人同时读,但不能同时写,那就上读🔐;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写🔐。总之,读的时候上读🔐,写的时候上写🔐。
一个面试题:一个缓存类!
网友评论