版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014252478/article/details/83587477
创建两个线程,观察并发时出现的错误:
package 测试;
public class TestThread {
public static void main(String[] args) {
Init();
}
public static void Init() {
//创建第一个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
System.out.println("yanghao");
}
}
}).start();
//创建第二个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
System.out.println("dingyan");
}
}
}).start();
}
}
由上测试运行:
可以看出:直接打印字符串看不出,并发时的错误,因此来按照字符打印
代码如下:
package 测试;
public class TestThread {
public static void main(String[] args) {
Init();
}
public static void Init() {
//创建第一个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
//System.out.println("yanghao");
Outer("yanghao");
}
}
}).start();
//创建第二个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
//System.out.println("dingyan");
Outer("dingyan");
}
}
}).start();
}
public static void Outer(String str){
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
}
}
测试得:
此时,问题就出现了:同时运行两个线程时,导致输出异常,杂乱
为了解决此问题,需要用到synchronized关键字,我们来试试:
ackage 测试;
public class TestThread {
public static void main(String[] args) {
Init();
}
public static void Init() {
//创建第一个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
//System.out.println("yanghao");
Outer1("yanghao");
}
}
}).start();
//创建第二个线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
//System.out.println("dingyan");
Outer2("dingyan");
}
}
}).start();
}
public static synchronized void Outer1(String str){
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
}
public static synchronized void Outer2(String str){
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
}
}
此时,测试会发现恢复正常:
在日常工作中使用最多的、最安全的,最理想的线程延时,还是利用线程池技术ScheduledExecutorService
实现方式类似,如下:
package 测试;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(String[] args) {
Init();
}
public static void Init() {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
//创建第一个线程
pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Outer1("yanghao");
}
}, 0, 2, TimeUnit.SECONDS);
//创建第二个线程
pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Outer2("yanghao");
}
}, 0, 2, TimeUnit.SECONDS);
}
public static synchronized void Outer1(String str){
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
}
public static synchronized void Outer2(String str){
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
}
}
测试结果:
synchronized关键字用完了,那么同步锁是什么呢?
看代码:
package 测试;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(String[] args) {
Init();
}
public static void Init() {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
//创建第一个线程
pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Outer1("yanghao");
}
}, 0, 2, TimeUnit.SECONDS);
//创建第二个线程
pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Outer1("dingyan");
}
}, 0, 2, TimeUnit.SECONDS);
}
private static String token = "";
public static synchronized void Outer1(String str){
synchronized (token) { //定义一个锁
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
System.out.println("");
}
}
public static synchronized void Outer2(String str){
synchronized (token) { //定义一个锁
int length = str.length();
for (int i=0; i<length; i++){
System.out.print(str.charAt(i));
}
System.out.println("");
}
}
}
测试知道,同样实现了同步:
同步锁,就是在执行的地方创建同步块,将需要执行的代码放入其中,来保证代码独立运行,不受干扰。
那么token 是啥呢?
就是一把锁,简单理解:
同步代码块的锁是任意对象。只要不同的线程都执行同一个同步代码块的时候,这个锁随便设。