最近正好有时间,想深入了解一下高并发相关知识,本人前端,在空闲时间也在写java,但是只停留在会写的地步,一直没有深入研究。写博文一是为了加深印象,也是共同学习和交流。写的不好,纯当日志。参考慕课网的教学视频
Multi-threaded programs may often come to a situation where multiple threads try to access the same resources and finally produce erroneous and unforeseen results. So it needs to be made sure by some synchronization method that only one thread can access the resource at a given point of time. Java provides a way of creating threads and synchronizing their task by using synchronized blocks. Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at a time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.
多线程的程序经常会遇到由于抢占同一资源而产生一些错误或者不可预知的结果,这就需要程序在同一时间只能有一个线程获取资源(同步)。 java利用同步锁(synchronized blocks)产生线程和同步任务。同步锁用于同步一些对象,所有的同步锁同步相同的对象只会有一个线程执行。其他的线程在试图进入访问同步锁的同时会被阻止,直到当前的锁被释放掉(这段翻译的不大顺畅:大致意思是,多个线程访问资源的时候,被Synchronized标记的类或者对象会产生一个synchronized lock,一旦产生这个锁,其他的线程就不能访问该资源,直到当前的锁被释放掉为止)
/**
- @Author kaka
- @Description //描述不控制高并发的后果
- @Date 2018/12/26 11:03 AM
- @Version 1.0.0
- @return String
**/
public class MyThread implements Runnable {
static int count = 1;
static MyThread myThread = new MyThread();
public static void main(String[] args) {
Thread t1 = new Thread(myThread);
Thread t2 = new Thread(myThread);
t1.start(); // 开启
t2.start(); // 开启
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
@Override
public void run() {
// 十万次更新count
for(int j=0;j<10000;j++){
count++;
}
}
}
我们想要得到的count结果是 10000*2 ,但几次执行的结果分别是 15578,15359,16784 … 析: count ++ 有三个步骤
读取count
count +1
将 +1之后的count写入内存 由于count++实际上是分三步执行,那么在多线程的情况下,任何步骤都会被打断,因此就有多线程操作一样的数据结果的可能(eg: A线程操作9+1 = 10,尚未存入内存,B线程也读取到 9+1 = 10,A,B线程同时存入内存,想要的结果是10和11都存入内存,实际上两次存入的结果都是10,因此最终打印的结果小于10000*2,这就是不控制并发导致的后果)
synchronized的用法(对象锁 和 类锁)
对象锁
代码块形式
synchronized ( this 或者 实例对象)
/**
* @Author kaka
* @Description 对象锁的代码块形式
* @Date 2018/12/26 2:13 PM
* @Version 1.0.0
**/
public class MyThread1 implements Runnable {
static int count = 0;
static MyThread1 myThread1 = new MyThread1();
public static void main(String[] args) {
Thread t1 = new Thread(myThread1);
Thread t2 = new Thread(myThread1);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("finished"+ count);
}
@Override
public void run() {
//synchronized手动指定代码块
synchronized (this){
System.out.println(Thread.currentThread().getName()+ " start");
for(int i=0;i<100000;i++){
count++;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ " over");
}
}
}
方法修饰符形式
/**
* @Author KAKA
* @Description 方法修饰符形式
* @Date 2018/12/26 2:42 PM
* @Version 1.0.0
**/
public class MyThread2 implements Runnable {
static MyThread2 myThread2 = new MyThread2();
static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(myThread2);
Thread t2 = new Thread(myThread2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("count= "+count);
}
@Override
public void run() {
method();
}
//synchronized修饰普通方法,锁对象默认为this
public synchronized void method(){
System.out.println(Thread.currentThread().getName()+ " start");
for(int i=0;i<100000;i++){
count++;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ " over");
}
}
类锁
concept: java可能有很多实例对象,但只有一个Class对象(不同的线程去请求同一资源,本质上是请求同一个Class对象),类锁只能在同一时刻被同一个对象拥有。
形式1 ( synchronized修饰静态方法 )
/**
* @Author KAKA
* @Description synchronized 修饰静态方法
* @Date 2018/12/26 2:42 PM
* @Version 1.0.0
**/
public class MyThread3 implements Runnable {
static MyThread3 instance1 = new MyThread3();
static MyThread3 instance2 = new MyThread3();
static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("count= "+count);
}
@Override
public void run() {
method();
}
//synchronized 修饰静态方法
public static synchronized void method(){
System.out.println(Thread.currentThread().getName()+ " start");
for(int i=0;i<100000;i++){
count++;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ " over");
}
}
形式2( synchronized(*.class)代码块 )
/**
* @Author KAKA
* @Description 方法修饰符形式
* @Date 2018/12/26 2:42 PM
* @Version 1.0.0
**/
public class MyThread4 implements Runnable {
static MyThread4 myThread1 = new MyThread4();
static MyThread4 myThread2 = new MyThread4();
static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(myThread2);
Thread t2 = new Thread(myThread2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("count= "+count);
}
@Override
public void run() {
method();
}
//synchronized锁对象为*.class
public void method(){
synchronized(MyThread4.class){
System.out.println(Thread.currentThread().getName()+ " start");
for(int i=0;i<100000;i++){
count++;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ " over");
}
}
}