多线程在并发处理共享数据,会对数据进行修改或者读取导致共享的数据发生了无法预料的变化。案例:有三个窗口同时售票,每个窗口都共享着一定票数,某个线程操着当前票数还没有对其改变,就有其他线程把当前票就修改了,就会出现负票情况,这就是线程不安全的。
解决方案synchronized 解决
synchronized直译同步的意思,有两种方法1、同步方法 2、同步代码块;注: synchronized(?),括号里面的?是同一个对象,我们称之为锁。锁是一个对象该对象可以是任意对象但必须保证是同一对象。举例:火车上有个厕所当我们去上厕所是需要挂锁别人没钥匙打不开只有你上完厕所把锁打开别人才能进去继续上锁一次类推。
目录
一、同步代码块
1、实现接口
(1) 当前Object就是锁对象,该S1对象只new 了一次,Object也只new了一次,所以他是同一把锁,也可以用this
package cn;
class S1 implements Runnable{
private int t=200;
Object o=new Object();
@Override
public void run() {
synchronized(o){
while(true){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}else{
break;
}
}
}
}
}
public class SynchronizedTest {
public static void main(String[] args) {
S1 s = new S1();
Thread t=new Thread(s);
Thread t1=new Thread(s);
Thread t2=new Thread(s);
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}
(2)S1.class在JVM加载过程中只加载一次
package cn;
class S1 implements Runnable{
private int t=200;
@Override
public void run() {
synchronized(S1.class){
while(true){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}else{
break;
}
}
}
}
}
public class SynchronizedTest {
public static void main(String[] args) {
S1 s = new S1();
Thread t=new Thread(s);
Thread t1=new Thread(s);
Thread t2=new Thread(s);
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}
2、继承
(1)S2.class在JVM加载过程中只加载一次,可以用private static Object o=new Object,静态的,不能像接口用this这是指当前对象,当前对象s2被new 了三次,不是同一把锁
package cn;
class S2 extends Thread{
private static int t=200;
private static Object o=new Object();
@Override
public void run() {
synchronized(o){
while(true){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}else{
break;
}
}
}
}
}
public class SynchronizedDemo {
public static void main(String[] args) {
S2 t=new S2();
S2 t1=new S2();
S2 t2=new S2();
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}
package cn;
class S2 extends Thread{
private static int t=200;
@Override
public void run() {
synchronized(S2.class){
while(true){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}else{
break;
}
}
}
}
}
public class SynchronizedDemo {
public static void main(String[] args) {
S2 t=new S2();
S2 t1=new S2();
S2 t2=new S2();
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}
二、同步方法
1、实现接口
(1)这相当于锁是this
package cn;
class S1 implements Runnable{
private int t=200;
public void run() {
while (true) {
titck();
}
}
private synchronized void titck(){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}
}
}
public class SynchronizedTest {
public static void main(String[] args) {
S1 s = new S1();
Thread t=new Thread(s);
Thread t1=new Thread(s);
Thread t2=new Thread(s);
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}
2、继承
(2)相当于锁是S2.class
package cn;
class S2 extends Thread{
private static int t=200;
@Override
public void run() {
while (true) {
titck();
}
}
private static synchronized void titck(){
if(t>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 票数为:"+t);
t--;
}
}
}
public class SynchronizedDemo {
public static void main(String[] args) {
S2 t=new S2();
S2 t1=new S2();
S2 t2=new S2();
t.setName("1号口");
t1.setName("2号口");
t2.setName("3号口");
t.start();
t1.start();
t2.start();
}
}