线程同步
- 多线程并行访问时,会出现数据安全问题。
- 多个线程同时访问一个共享数据时,如果不加以控制,可能会出现数据错误的问题。尤其是在金融领域。
实现同步时,数据报错的案例
public class Test{
public static void main(String[] args) {
Account account = new Account();
Thread t1 = new Thread(account,"线程1");
Thread t2 = new Thread(account,"线程2");
t1.start();
t2.start();
}
}
class Account implements Runnable{
private static int num;
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num++;
System.out.println(Thread.currentThread().getName() + "是当前的第"+num+"个访客。");
}
}
- 可以通过 synchronized 修饰方法来实现线程同步
- 每个 Java 对象都有一个内置锁,内置锁会保护使用 synchronized 关键字修饰的方法,要调用该方法就必须先获得内置锁,否则就处于阻塞状态。
实例一:
package com.chenny.test;
public class Test{
public static void main(String[] args) {
Account account = new Account();
Thread t1 = new Thread(account,"线程1");
Thread t2 = new Thread(account,"线程2");
t1.start();
t2.start();
}
}
class Account implements Runnable{
private static int num;
@Override
//synchronized内置锁
public synchronized void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num++;
System.out.println(Thread.currentThread().getName() + "是当前的第"+num+"个访客。");
}
}
- synchronized可以修饰实例方法,也可以修饰静态方法,还可以修饰代码块,从而实现线程同步。
实例二:
package com.chenny.test;
public class SynchronizedTest{
public static void main(String[] args) {
for(int i=0;i<10;i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
test();
}
});
thread.start();
}
}
//如果这里不加synchronized,start...与end...将不能成对出现。
public static synchronized void test() {
System.out.println("start......");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end.......");
}
}
阅读下面代码,思考为什么synchronized会失效?
public class SynchronizedTest{
public static void main(String[] args) {
for(int i=0;i<10;i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
SynchronizedTest st = new SynchronizedTest();
st.test();
}
});
thread.start();
}
}
public synchronized void test() {
System.out.println("start......");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end.......");
}
}
简单来说,synchronized锁定的是资源而不是方法,只有当它是公共资源时,锁住它,才有控制作用。
实例三:
- 在静态方法中添加同步代码块
//()中需要设置加锁的资源,静态方法属于类的方法,不属于任何一个实例对象,
// 所以静态方法中的synchronized只能锁定类,不能锁定实例对象
synchronized(){
//此处填写代码块
}
package com.chenny.test;
public class SynchronizedTest{
public static void main(String[] args) {
for(int i=0;i<10;i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
test();
}
});
thread.start();
}
}
public static void test() {
synchronized(SynchronizedTest.class) { //SynchronizedTest.class 获取的是Synchronized在内存中运行时类,每个运行时类只有一份。
System.out.println("start......");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end.......");
}
}
}
实例四:
- 实例方法中也可以使用synchronized实现同步代码块。
public class SynchronizedTest{
public static void main(String[] args) {
for(int i=0;i<10;i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
SynchronizedTest st = new SynchronizedTest();
st.test();
}
});
thread.start();
}
}
public void test() {
synchronized(SynchronizedTest.class) {
System.out.println("start......");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end.......");
}
}
}