1并发

package com.bjsxt.base.sync001;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
 * synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"
 * @author alienware
 *
 */
public class MyThread extends Thread{
	
	private int count = 5 ;
	
	//synchronized加锁
	public void run(){
		count--;
		System.out.println(this.currentThread().getName() + " count = "+ count);
	}
	
	public static void main(String[] args) {
		/**
		 * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),
		 * 		一个线程想要执行synchronized修饰的方法里的代码:
		 * 		1 尝试获得锁
		 * 		2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,
		 * 		   而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)
		 */
		MyThread myThread = new MyThread();
		Thread t1 = new Thread(myThread,"t1");
		Thread t2 = new Thread(myThread,"t2");
		Thread t3 = new Thread(myThread,"t3");
		Thread t4 = new Thread(myThread,"t4");
		Thread t5 = new Thread(myThread,"t5");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
	}
}

执行结果:

 

1线程安全的概念:

当多个线程访问一个类(对象或者方法)时,这个类始终能表现出正确的行为,那么这个类()对象或者方法

就是线程安全的

synchronized 可以在任意对象以及方法上加锁,饿加锁的代码叫‘互斥区’或者‘临界区

package com.bjsxt.base.sync001;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
 * synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"
 * @author alienware
 *
 */
public class MyThread extends Thread{
	
	private int count = 5 ;
	
	//synchronized加锁
	public synchronized void run(){
		count--;
		System.out.println(this.currentThread().getName() + " count = "+ count);
	}
	
	public static void main(String[] args) {
		/**
		 * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),
		 * 		一个线程想要执行synchronized修饰的方法里的代码:
		 * 		1 尝试获得锁
		 * 		2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,
		 * 		   而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)
		 */
		MyThread myThread = new MyThread();
		Thread t1 = new Thread(myThread,"t1");
		Thread t2 = new Thread(myThread,"t2");
		Thread t3 = new Thread(myThread,"t3");
		Thread t4 = new Thread(myThread,"t4");
		Thread t5 = new Thread(myThread,"t5");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
	}
}

执行结果:

总结:

当多个线程访问myThread方法时,以排队的方法进行处理(排队是按照cpu分配的先后顺序而定的,一个线程想要执行synchronized修饰的方法里的代码时,首先尝试获得锁,如果拿到锁,执行synchronized代码体的内容,拿不到锁时,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且时多个线程同时争取这把锁(也就是锁竞争的问题))

=================================

2多个线程多个锁:多个线程,每个线程都可以拿到自己指定的锁,分别获得锁后,执行synchronized方法体的内容

package com.bjsxt.base.sync002;
/**
 * 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,
 * 所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),
 * 
 * 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。
 * @author alienware
 *
 */
public class MultiThread {

	private int num = 0;
	
	/** static */
	public synchronized void printNum(String tag){
		try {
			
			if(tag.equals("a")){
				num = 100;
				System.out.println("tag a, set num over!");
				Thread.sleep(1000);
			} else {
				num = 200;
				System.out.println("tag b, set num over!");
			}
			
			System.out.println("tag " + tag + ", num = " + num);
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	//注意观察run方法输出顺序
	public static void main(String[] args) {
		
		//俩个不同的对象
		final MultiThread m1 = new MultiThread();
		final MultiThread m2 = new MultiThread();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				m1.printNum("a");
			}
		});
		
		Thread t2 = new Thread(new Runnable() {
			@Override 
			public void run() {
				m2.printNum("b");
			}
		});		
		
		t1.start();
		t2.start();
		
	}
	
	
	
	
}

每个对象都有自己的锁

2.2

同步:synchronized

同步的概念就是共享,如果不是共享的资源,就没不要进行同步

异步:asynchronized

异步的概念就是独立,相互之间不受任何影响

同步的目的就是线程安全,对于线程安全来说,需要满足两个特性:原子性(同步),可见行

package com.bjsxt.base.sync003;

/**
 * 对象锁的同步和异步问题
 * @author alienware
 *
 */
public class MyObject {

	public synchronized void method1(){
		try {
			System.out.println(Thread.currentThread().getName());
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/** synchronized */
	public void method2(){
			System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		
		final MyObject mo = new MyObject();
		
		/**
		 * 分析:
		 * t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
		 * t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
		 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method1();
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method2();
			}
		},"t2");
		
		t1.start();
		t2.start();
		
	}
	
}

两个同时执行,因为第二个方法没有锁,两个互不影响,直接执行

 

package com.bjsxt.base.sync003;

/**
 * 对象锁的同步和异步问题
 * @author alienware
 *
 */
public class MyObject {

	public synchronized void method1(){
		try {
			System.out.println(Thread.currentThread().getName());
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/** synchronized */
	public synchronized void method2(){
			System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		
		final MyObject mo = new MyObject();
		
		/**
		 * 分析:
		 * t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
		 * t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
		 */
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method1();
			}
		},"t1");
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				mo.method2();
			}
		},"t2");
		
		t1.start();
		t2.start();
		
	}
	
}

ti执行完后,过4秒执行t2

两个方法都加里锁,一个实例对象执行两个方法时,都要争夺锁,都一个方法的锁释放完毕,在执行另一个方法。

示例总结:

a线程先持有object对象的lock锁,b线程如果在这个时候调用对象中的同步(synchronized)方法需等待,也就是同步

a线程先持有object对象的lock锁,b线程可以以异步的方式调用对象中的非synchronized修饰得分方法

 

======================================

3对于对象的同步和异步的方法,设计程序时,一定要考虑问题的整体。不然会出现数据不一致的错误,很经典的就是脏读

package com.bjsxt.base.sync004;
/**
 * 业务整体需要使用完整的synchronized,保持业务的原子性。
 * @author alienware
 *
 */
public class DirtyRead {

	private String username = "bjsxt";
	private String password = "123";
	
	public synchronized void setValue(String username, String password){
		this.username = username;
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		this.password = password;
		
		System.out.println("setValue最终结果:username = " + username + " , password = " + password);
	}
	
	public void getValue(){
		System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password);
	}
	
	
	public static void main(String[] args) throws Exception{
		
		final DirtyRead dr = new DirtyRead();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				dr.setValue("z3", "456");		
			}
		});
		t1.start();
		Thread.sleep(1000);
		
		dr.getValue();
	}
	
	
	
}

在setvalue时,不希望getvlaue

package com.bjsxt.base.sync004;
/**
 * 业务整体需要使用完整的synchronized,保持业务的原子性。
 * @author alienware
 *
 */
public class DirtyRead {

	private String username = "bjsxt";
	private String password = "123";
	
	public synchronized void setValue(String username, String password){
		this.username = username;
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		this.password = password;
		
		System.out.println("setValue最终结果:username = " + username + " , password = " + password);
	}
	
	public synchronized void getValue(){
		System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password);
	}
	
	
	public static void main(String[] args) throws Exception{
		
		final DirtyRead dr = new DirtyRead();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				dr.setValue("z3", "456");		
			}
		});
		t1.start();
		Thread.sleep(1000);
		
		dr.getValue();
	}
	
	
	
}

示例总结:

在我们对一个对象的方法加锁时,需要考虑业务的整体行,即setValue/getValue方法 同时加锁时,保证

业务的原子性,不然会出现业务错误。

 

=============================

synchronized锁重入:

在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时可以再次得到该对象的锁。

package com.bjsxt.base.sync005;
/**
 * synchronized的重入
 * @author alienware
 *
 */
public class SyncDubbo1 {

	public synchronized void method1(){
		System.out.println("method1..");
		method2();
	}
	public synchronized void method2(){
		System.out.println("method2..");
		method3();
	}
	public synchronized void method3(){
		System.out.println("method3..");
	}
	
	public static void main(String[] args) {
		final SyncDubbo1 sd = new SyncDubbo1();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				sd.method1();
			}
		});
		t1.start();
	}
}

package com.bjsxt.base.sync005;
/**
 * synchronized的重入
 * @author alienware
 *
 */
public class SyncDubbo2 {

	static class Main {
		public int i = 10;
		public synchronized void operationSup(){
			try {
				i--;
				System.out.println("Main print i = " + i);
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	static class Sub extends Main {
		public synchronized void operationSub(){
			try {
				while(i > 0) {
					i--;
					System.out.println("Sub print i = " + i);
					Thread.sleep(100);		
					this.operationSup();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sub sub = new Sub();
				sub.operationSub();
			}
		});
		
		t1.start();
	}
	
	
}

父类和子类都有synchronized修饰时,也是没有问题的

=========================================================

package com.bjsxt.base.sync005;
/**
 * synchronized异常
 * @author alienware
 *
 */
public class SyncException {

	private int i = 0;
	public synchronized void operation(){
		while(true){
			try {
				i++;
				Thread.sleep(100);
				System.out.println(Thread.currentThread().getName() + " , i = " + i);
				if(i == 10){
					Integer.parseInt("a");
				}
			} catch (Exception e) {//InterruptedException
				e.printStackTrace();
				//throw new RuntimeException();
				System.out.print("记录日志");
				continue;
			}
		}
	}
	
	public static void main(String[] args) {
		
		final SyncException se = new SyncException();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				se.operation();
			}
		},"t1");
		t1.start();
	}
	
	
}

package com.bjsxt.base.sync005;
/**
 * synchronized异常
 * @author alienware
 *
 */
public class SyncException {

	private int i = 0;
	public synchronized void operation(){
		while(true){
			try {
				i++;
				Thread.sleep(100);
				System.out.println(Thread.currentThread().getName() + " , i = " + i);
				if(i == 10){
					Integer.parseInt("a");
					//throw new RuntimeException();
				}
			} catch (Exception e) {//InterruptedException
				e.printStackTrace();
				throw new RuntimeException();
			}
		}
	}
	
	public static void main(String[] args) {
		
		final SyncException se = new SyncException();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				se.operation();
			}
		},"t1");
		t1.start();
	}
	
	
}

package com.bjsxt.base.sync005;
/**
 * synchronized异常
 * @author alienware
 *
 */
public class SyncException {

	private int i = 0;
	public synchronized void operation(){
		while(true){
			try {
				i++;
				Thread.sleep(100);
				System.out.println(Thread.currentThread().getName() + " , i = " + i);
				if(i == 10){
					Integer.parseInt("a");
					//throw new RuntimeException();
				}
			} catch (InterruptedException e) {//InterruptedException
				e.printStackTrace();
				//throw new RuntimeException();
			}
		}
	}
	
	public static void main(String[] args) {
		
		final SyncException se = new SyncException();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				se.operation();
			}
		},"t1");
		t1.start();
	}
	
	
}

重要:当在i-=10时,抛出一个异常,他还会继续往下走,把下边的走完!!!Exception  可以在catch中记录一下日志

当整个方法是一个整体,一个失败,会影响下边的程序,抛出InterruptedException,他会停止走下边

当整个方法是一个整体,一个失败,会影响下边的程序,在catch中抛出异常:throw new RuntimeException();他会停止走下边

 

===========================

volatile:

主要作用:使变量在多个线程间可见

有一个共享变量,a=0,开了两个线程t1,t2.t1对a进行了修改,t2线程也对a进行了修改。两个线程直接是互不可见的。

希望a保持一个一致性,t1改成了20,t2也应该改成20.volitile可以起到这个作用。

没有volatile时,我们用锁做到了这个效果,保持了a变量的一致性。但是这样的效率低,因为同一时间只有一个线程能操作共有的变量,其他线程只能等着

package com.bjsxt.base.sync007;

public class RunThread extends Thread{

	private  boolean isRunning = true;//private volatile boolean isRunning = true;
	private void setRunning(boolean isRunning){
		this.isRunning = isRunning;
	}
	
	public void run(){
		System.out.println("进入run方法..");
		int i = 0;
		while(isRunning == true){
			//..
		}
		System.out.println("线程停止");
	}
	
	public static void main(String[] args) throws InterruptedException {
		RunThread rt = new RunThread();
		rt.start();
		Thread.sleep(1000);
		rt.setRunning(false);
		System.out.println("isRunning的值已经被设置了false");
	}
	
	
}

虽然设置成了false,但是程序并没有停止。

原因:jdk1.5后,对每个线程加了一个运行空间,装主线程的一些引用变量。直接去父本取

装了isRunning=true.在变量上加volatile,他就会停止了。

==========================================

package com.bjsxt.base.sync007;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * volatile关键字不具备synchronized关键字的原子性(同步)
 * @author alienware
 *
 */
public class VolatileNoAtomic extends Thread{
	private static volatile int count;
	//private static AtomicInteger count = new AtomicInteger(0);
	private static void addCount(){
		for (int i = 0; i < 1000; i++) {
			count++ ;
			//count.incrementAndGet();
		}
		System.out.println(count);
	}
	
	public void run(){
		addCount();
	}
	
	public static void main(String[] args) {
		
		VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
		for (int i = 0; i < 10; i++) {
			arr[i] = new VolatileNoAtomic();
		}
		
		for (int i = 0; i < 10; i++) {
			arr[i].start();
		}
	}
	
	
	
	
}

volatile关键字不具备synchronized关键字的原子性(同步)

package com.bjsxt.base.sync007;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * volatile关键字不具备synchronized关键字的原子性(同步)
 * @author alienware
 *
 */
public class VolatileNoAtomic extends Thread{
	//private static volatile int count;
	private static AtomicInteger count = new AtomicInteger(0);
	private static void addCount(){
		for (int i = 0; i < 1000; i++) {
			//count++ ;
			count.incrementAndGet();
		}
		System.out.println(count);
	}
	
	public void run(){
		addCount();
	}
	
	public static void main(String[] args) {
		
		VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
		for (int i = 0; i < 10; i++) {
			arr[i] = new VolatileNoAtomic();
		}
		
		for (int i = 0; i < 10; i++) {
			arr[i].start();
		}
	}
	
	
	
	
}

总结:volatile虽然拥有多个线程之间的可见性,但是不具备同步性(也就是原子性),可以算上一个轻量级的synchronized。性能比synchronized强很多,不会造成阻塞。比如netty的底层代码就大量使用了volatutle,可见netty性能一定时不错的,但需要注意的是,一般volatitle用于只针对多个线程可见的变量操作,并不能替代synchronized的同步功能。

 

volatile只具有可见性,没有原子性。要实现原子性建议使用atomic类的系列对象,支持原子性操作

(注意 atomic类只保证本身方法原子性没,并不能保持多次操作的原子性)

=============================

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL的UPDATE SET语句在并发环境中可能会造成一些问题。下面是一些可能出现的问题和解决方案。 首先,当多个客户端同时执行UPDATE SET语句时,可能会发生冲突。例如,如果两个客户端同时更新同一行的某个字段,可能会导致数据不一致。为了避免这个问题,可以使用行级锁或事务来确保原子性。使用行级锁意味着在更新数据的时候,其他客户端将无法访问该行的数据。事务也可以确保更新操作是原子的,即要么全部成功,要么全部失败,可以使用START TRANSACTION和COMMIT语句来定义更新操作的范围。 其次,并发更新操作可能会导致死锁的问题。当多个客户端同时尝试更新多个表中的数据,并且更新操作之间存在依赖关系时,可能会发生死锁。为了避免死锁,可以使用死锁检测和回滚机制。MySQL内部提供了死锁检测机制,当检测到死锁时,会选择一个事务进行回滚,然后让其他事务继续执行。 最后,并发更新操作也可能带来性能问题。当多个客户端同时更新大量数据时,可能会导致数据库性能下降。为了提高性能,可以使用合适的索引和优化查询语句来减少不必要的扫描和IO操作。此外,合理设置数据库的连接池和线程池参数也能够提升并发更新的性能。 综上所述,MySQL的UPDATE SET语句在并发环境中可能会遇到一些问题,例如数据冲突、死锁和性能问题。但通过使用行级锁、事务、死锁检测和回滚机制,以及合理设置索引和优化查询语句,可以解决这些问题并提高数据库的并发性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值