Synchronized
在java语言中存在两种内建的synchronized语法:synchronized语句和synchronized方法。synchronized将并行改为串行,当然会影响程序的执行效率,执行速度会受到影响。其次synchronized操作线程的堵塞,也就是由操作系统控制CPU的内核进行上下文的切换,这个切换本身也是耗时的。所以使用synchronized关键字会降低程序的运行效率。
三个售票窗口同时出售20张票
public class Test1 {
public static void main(String[] args) {
for(int i=1;i<=3;i++) {
new 售票线程(i+"号窗口").start();
}
}
}
class 售票线程 extends Thread{
private String name;
private static Integer count=20;//票池,static保证多个线程对象共享一个票池
private static final String aaa="bbbb";
public 售票线程(String name) {
this.name = name;
}
@Override
public void run() {
while(count>0) {
// System.out.println(this.name+count+"开始售票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (aaa) {
if(count>0) {
System.out.println(this.name+"售出第 "+count+" 号票");
count--;
// System.out.println(this.name+":"+count);
}else {
System.out.println(this.name+"票已售尽");
}
// System.out.println(this.name+count+"结束售票");
}
}
}
}
Synchronized用于实现同步处理,保证共享数据的安全性
数据有安全性问题的原因:1、共享数据 2、修改数据Synchronized相对于volatile是重量级的线程安全的方法,可以保证3大特性:原子性、可见性、有序性
synchronized将并行改为串行
-用于静态方法,锁对象为当前类public synchronized static void pp(){}
-用于非静态方法,锁对象为当前类的对象
public synchronized void pp(){}
-用于代码块,锁对象为指定的对象 该对象可以自定义
synchronized(obj){}
同步代码块
import java.util.concurrent.locks.Lock;
//同步代码块
public class A {
public static void main(String[] args) {
for(int i=1;i<=3;i++) {
new MyThread(i+"号窗口").start();
}
}
}
class MyThread extends Thread{
private String name;
private static int counter=20;
private static final String LOCK="bbbb";
public MyThread(String name) {
this.name=name;
}
@Override
public void run() {
while(counter>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (LOCK) {//锁的数量一定要比资源少,要把资源锁住,用name不可以,因为name是3个窗口,不能锁住,锁有一把;只要是引用类型都可以,
if(counter>0) {
System.out.println(this.name+"售出第"+counter+"号票");
synchronized (LOCK) {
counter--;
}
System.out.println(this.name+":"+counter);
}else {
System.out.println(this.name+":"+"票已售尽");
}
}
}
}
}
同步方法
public class A2 {
public static void main(String[] args) throws Exception {
NumOper no=new NumOper(100);
Thread[] th=new Thread[4];
for (int i = 0; i < 2; i++) {
th[i*2]=new Thread(() -> {
for(int k=0;k<50;k++) {
no.add();
}
});
th[i*2].start();
th[i*2+1]=new Thread(() -> {
for(int k=0;k<50;k++) {
no.sub();
}
});
th[i*2+1].start();
}
for(Thread tmp:th)
tmp.join();
System.out.println("Main:"+no.getNum());
}
}
/*
* 以new出来的NumOper对象充当锁,当前对象内的synchronized方法在不同线程调用时互斥,
* 但是可以直接访问非synchronized方法
*
* 注意synchronized允许持有锁的线程重入
*/
class NumOper {
private int num;
public NumOper(int num) {//synchronized不能添加到构造器上
this.num = num;
}
public synchronized void add() {
System.out.println(Thread.currentThread() + "Thread......begin" + this.num);
this.num++;
// sub();
System.out.println(Thread.currentThread() + "Thread......end" + this.num);
}
public synchronized void sub() {
System.out.println(Thread.currentThread() + "Thread......begin" + this.num);
this.num--;
System.out.println(Thread.currentThread() + "Thread......end" + this.num);
}
public int getNum() {
return this.num;
}
}
同步静态方法
统计指定类的创建次数 ,代码如下:
public class A3 {
public static void main(String[] args) {
for(int i=0;i<5;i++) {
new Thread(()->{
for(int k=0;k<10;k++) {
new S3();
}
}).start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(S3.getCounter());//
}
}
class S3{
private static int counter=0;
public S3() {
add();
}
private synchronized static void add() {//static 不可以用this
System.out.println(Thread.currentThread()+"开始创建操作"+counter);
counter++;
System.out.println(Thread.currentThread()+"完成创建操作"+counter);
}
public static int getCounter() {
return counter;
}
}
使用类锁,所以不管new了多少个对象,都可以得到互斥的效果
public class A4 {
public static void main(String[] args) {
new Thread(()->{
for(int i=0;i<20;i++) {
S4 ss=new S4();
ss.pp1();
}
}).start();
new Thread(()->{
for(int i=0;i<20;i++) {
S4 ss=new S4();
ss.pp1();
}
}).start();
}
}
class S4{
public synchronized static void pp1() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public void pp2() {}
}
使用的是对象锁,所以只能new一个对象,都可以得到互斥的效果。如果创建多个则不能达到互斥目的
public class A41 {
public static void main(String[] args) {
S41 ss=new S41();
new Thread(()->{
// S41 ss=new S41();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp2();
}
}).start();
new Thread(()->{
// S41 ss=new S41();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp2();
}
}).start();
}
}
//类S4为锁对象
class S41{
public synchronized static void pp1() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized void pp2() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized void pp3() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
}
使用的是不同的锁,所以thread0和thread1不能达到互斥的效果。
public class A42 {
public static void main(String[] args) {
S42 ss=new S42();
new Thread(()->{
// S41 ss=new S41();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
// ss.pp2();//非static方法 --对象锁 ss
ss.pp3();
}
}).start();
new Thread(()->{
// S41 ss=new S41();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp1();//static方法 --类锁 S42.class
ss.pp4();
}
}).start();
}
}
//类S4为锁对象
class S42{
public synchronized static void pp1() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized void pp2() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized static void pp3() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized static void pp4() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
}
锁对象不一样会导致锁不住,一个是类锁,一个是对象锁
public class A44 {
public static void main(String[] args) {
S44 ss=new S44();
new Thread(()->{
// S44 ss=new S44();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
// ss.pp2();//非static方法 --对象锁 ss
ss.pp3();
}
}).start();
new Thread(()->{
// S44 ss=new S44();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp2();//非static方法 --对象锁 ss
}
}).start();
new Thread(()->{
// S44 ss=new S44();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp1();//static方法 --类锁 S42.class
}
}).start();
new Thread(()->{
// S44 ss=new S44();
for(int i=0;i<20;i++) {
// S41 ss=new S41();
ss.pp4();
}
}).start();
}
}
//类S4为锁对象
class S44{
public synchronized static void pp1() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized void pp2() {
System.out.println(Thread.currentThread()+"...begin..."+Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end..."+Thread.currentThread().getName());
}
public synchronized static void pp3() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
public synchronized static void pp4() {
System.out.println(Thread.currentThread()+"...begin...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"...end...");
}
}