
线程有时候回和其他线程共享一些资源,比如内存、数据库等。当多个线程同时读写同一份共享资源的时候,可能会发生冲突。这时候,我们就需要引入线程“同步”机制,即各位线程之间要有顺序使用,不能杂乱无章随意使用。
线程A
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private String context;
public ThreadA(String context) {
super();
this.context = context;
}
@Override
public void run() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
}
System.out.println();
}
}
线程B
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private String context;
public ThreadB(String context) {
super();
this.context = context;
}
@Override
public void run() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
}
System.out.println();
}
}
主线程
package threadTest.test7;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
new Thread(new ThreadA("12345678910")).start();
new Thread(new ThreadB("abcdefghijk")).start();
}
}
如果一般情况下分析结果应该为:
12345678910
abcdefghijk
但是某种情况下却出现:
也就是有些情况下线程A的for循环还未执行完,cpu就把资源给了线程B,结果就造成这样的问题
要用同步代码块的话需要一个锁,而且两个线程必须用同一个锁,我们对上面的代码进行改进:
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private String context;
private Object obj;//充当锁,并不具有业务意义
public ThreadA(String context,Object obj) {
super();
this.obj=obj;
this.context = context;
}
@Override
public void run() {
synchronized(obj) {//锁住obj
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println();
}
}
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private String context;
private Object obj;//充当锁,并不具有业务意义
public ThreadB(String context,Object obj) {
super();
this.obj=obj;
this.context = context;
}
@Override
public void run() {
synchronized(obj) {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println();
}
}
package threadTest.test7;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Object obj=new Object();
new Thread(new ThreadA("12345678910",obj)).start();
new Thread(new ThreadB("abcdefghijk",obj)).start();
}
}
为了cpu实现明显的切换效果,在每次循环中都加了Thread.sleep(1);,睡眠一毫秒
这样就能保证synchronized代码块中的代码能够执行完,而不会出现错误
synchronized 修饰方法,即锁定当前要执行的方法的对象
代码:
package threadTest.test8;
public class Node {
private String context;
public Node(String context) {
super();
this.context = context;
}
public void p() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
}
}
package threadTest.test8;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private Node n;
public ThreadA(Node n) {
super();
this.n=n;
}
@Override
public void run() {
n.p();
}
}
package threadTest.test8;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private Node n;
public ThreadB(Node n) {
super();
this.n=n;
}
@Override
public void run() {
n.p();
}
}
package threadTest.test8;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Node n=new Node("123456789");
new Thread(new ThreadA(n)).start();
new Thread(new ThreadB(n)).start();
}
}
执行结果:
发现没有达到目的
那么在Node类的p方法中加 synchronized 关键字如:
public synchronized void p() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
}
再次执行
达到了我们想要的目的
如果主线程改成:
package threadTest.test8;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Node n=new Node("123456789");
Node n2=new Node("abcdefghijk");
new Thread(new ThreadA(n)).start();
new Thread(new ThreadB(n2)).start();
}
}
发现结果为
原因就是因为 同步方法锁定的是当前要执行的方法的对象,但是n和n2不是同一个对象,所以并没有达到效果
总结: