多线程(一):线程互斥 和 Atomic包

本文详细探讨了在多线程环境下如何通过同步锁实现线程互斥,确保数据安全与正确性。同时,介绍了如何使用线程局部变量、共享数据的多线程访问策略,以及原子类在多线程操作中的应用。通过实例展示了线程并发库的使用,以解决多线程间的共享数据问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//线程互斥

public class Test4 {

	//经验学习:要用到共同数据(包括同步锁)或共同算法的若干方法应该归到同一个类身上,这样这几体现了高内聚和程序的健壮性
	//线程互斥
	public static void main(String[] args)  {
		//(用两个线程)实现向屏幕打印两个字符串,tom jerry。
		
		new Test4().init();
		//多线程代码块中(run方法内)要做到互斥效果,需要用到同一个对象锁.
	}
	
	/**
	 * 
	 * @author Administrator
	 * 打印字符类
	 */
	class OutPutToScreen{
		
		//this 锁:
		//synchronized 这个方法里的代码具有排他性
		//互斥效果一定要是同一个对象,这个例子中A线程用到OutPutToScreen print对象,B
		//线程也用到OutPutToScreen print对象,因此用此对象当锁,此外还可以用其他当锁,但一定要是与这两个线程无关的对象。
		public synchronized void print(String string){
			//如果不加synchronized则不会产生互斥效果,输出的字符串可能不完整
			int len = string.length();
			for(int i=0;i<len;i++){
				System.out.print(string.charAt(i));
			}
			System.out.println();
			
		}
	}
	
	/**
	 * run方法里面操作的是同一个对象。因此用到当前对象锁,当前对象在被线程占用时,其他线程无法操作。
	 */
	public void init(){
		OutPutToScreen print = new OutPutToScreen();
		
		new Thread(new Runnable() {
					@Override
					public void run() {
						while (true) {
							print.print("thread_test");
						}
					}
				}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
						print.print("tom_and_jerry");
				}
			}
		}).start();
		
	}
	

}

public class Test4_1 {

	public static void main(String[] args)  {
		//(用两个线程)实现向屏幕打印两个字符串,tom jerry。
		
		new Test4_1().init();
	}
	
	/**
	 * 
	 * @author Administrator
	 * 打印字符类
	 */
	class OutPutToScreen{
		
		//OutPutToScreen.class 锁:
		
		//互斥效果一定要是同一个对象,这个例子中A线程用到OutPutToScreen print对象,B
		
		public  void print(String string){
			//
			synchronized(OutPutToScreen.class){
				
				int len = string.length();
				for(int i=0;i<len;i++){
					System.out.print(string.charAt(i));
				}
				System.out.println();
			}
			
		}
		public  void print2(String string){
			synchronized(OutPutToScreen.class){
				int len = string.length();
				for(int i=0;i<len;i++){
					System.out.print(string.charAt(i));
				}
				System.out.println();
			}
			
		}
	}
	
	public void init(){
		OutPutToScreen print = new OutPutToScreen();
		OutPutToScreen print2 = new OutPutToScreen();
		
		new Thread(new Runnable() {
					@Override
					public void run() {
						while (true) {
							//线程操作不同对象
							print.print("thread_test");
						}
					}
				}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					//线程操作不同对象
						print2.print("tom_and_jerry");
				}
			}
		}).start();
		
	}

}

public class Test4_2 {

	public static void main(String[] args)  {
		//(用两个线程)实现向屏幕打印两个字符串,tom jerry。
		
		new Test4_2().init();
	}
	
	/**
	 * @author Administrator
	 * 打印字符类
	 */
	class OutPutToScreen{
		
		
		//互斥效果一定要是同一个对象
		
		public synchronized void print(String string){
			
			int len = string.length();
			for(int i=0;i<len;i++){
				System.out.print(string.charAt(i));
			}
			System.out.println();
			
		}
		public synchronized void print2(String string){
			int len = string.length();
			for(int i=0;i<len;i++){
				System.out.print(string.charAt(i));
			}
			System.out.println();
			
		}
	}
	
	
	public void init(){
		OutPutToScreen print = new OutPutToScreen();
		//下面这两个run方法里的代码要做到互斥。由于是2个不同的对象,
		new Thread(new Runnable() {
					@Override
					public void run() {
						while (true) {
							//同一个对象
							print.print("thread_test");
						}
					}
				}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
						//同一个对象
						print.print2("tom_and_jerry");
				}
			}
		}).start();
		
	}
}

public class Test4_3 {

	public static void main(String[] args)  {
		//(用两个线程)实现向屏幕打印两个字符串,tom jerry。
		
		new Test4_3().init();
	}
	
	/**
	 * @author Administrator
	 * 打印字符类
	 */
	static class OutPutToScreen{
		
		
		//互斥效果一定要是同一个对象
		
		public  void print(String string){
			synchronized(OutPutToScreen.class){
				
				int len = string.length();
				for(int i=0;i<len;i++){
					System.out.print(string.charAt(i));
				}
				System.out.println();
			}
			
		}
		public  void print2(String string){
			synchronized(OutPutToScreen.class){
				
				int len = string.length();
				for(int i=0;i<len;i++){
					System.out.print(string.charAt(i));
				}
				System.out.println();
			}
			
		}
		//静态方法只有跟字节码对象关联
		public static  void print3(String string){
			synchronized(OutPutToScreen.class){
				
				int len = string.length();
				for(int i=0;i<len;i++){
					System.out.print(string.charAt(i));
				}
				System.out.println();
			}
			
		}
	}
	
	public void init(){
		OutPutToScreen print = new OutPutToScreen();
		//下面三个线程中的代码做到了互斥效果
		new Thread(new Runnable() {
					@Override
					public void run() {
						while (true) {
							//同一个对象
							print.print("thread_test");
						}
					}
				}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
						//同一个对象
						print.print2("tom_and_jerry");
				}
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					//同一个对象 ,静态方法
					print.print3("lilei_and_hanmeimei");
				}
			}
		}).start();
		
	}
}

//线程范围内共享变量

import java.util.Random;
/**
 * 线程范围内的共享变量
 */
public class Test5 {
	
	Random r = new Random();
	
	//threadLocal放的数据就是当前线程的数据。如果遇到多个变量,则可以将这些变量封装到一个类中。(ThreadLocal<Object>)
	ThreadLocal<String> threadLocal = new ThreadLocal<String>();
	//ThreadLocal 实现线程范围的共享变量.(一个线程一个数据)
	public static void main(String[] args) {
		
		//单例。。。
		
		new Test5().test();
	}
	
	public void test(){
		new Thread(new AGet()).start();
		new Thread(new BGet()).start();
		new Thread(new CGet()).start();
	}
	
	//读数据
	class AGet implements Runnable{

		@Override
		public void run() {
			String temp = String.valueOf(r.nextInt(100));
			temp = temp + "temp";
			threadLocal.set(temp);
			print();
		}
		
		public void print(){
			System.out.println("AGet print:"+threadLocal.get());
		}
		
		
	}
	//读数据
	class BGet implements Runnable{
		
		@Override
		public void run() {
			String temp = String.valueOf(r.nextInt(100));
			temp = temp + "temp";
			threadLocal.set(temp);
			print();
		}
		public void print(){
			System.out.println("BGet print:"+threadLocal.get());
		}
	}
	//写数据
	class CGet implements Runnable{
		
		@Override
		public void run() {
			String temp = String.valueOf(r.nextInt(100));
			temp = temp + "temp";
			threadLocal.set(temp);
			print();
		}
		public void print(){
			System.out.println("CSet print:"+threadLocal.get());
		
		}
	}

}

//多线程之间共享数据方式

public class Test6 {

	public static void main(String[] args) {
		//多线程之间共享数据的方式:
		//1:如果每个线程执行的代码相同,可以用同一个Runnable对象,这个Runnable对象中持有那个共享数据

		TicketSell ticketSell = new TicketSell();
		
		new Thread(ticketSell).start();
		new Thread(ticketSell).start();
		
		//2:如果每个线程执行的代码不同,这个时候需要用不同的Runnable对象,有下面方式实现
		//runnable对象之间的数据共享
		//--将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象,
		//每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各种操作的互斥和通信。

	}

	static class TicketSell implements Runnable{
		private int count = 10000;
		
		/**
		 * 卖票
		 */
		public synchronized void decrement(){
			//模拟
			count --;
		}
		
		@Override
		public void run() {
			while(true){
				//业务操作
			}
		}
	}
}

//线程并发库:java.util.concurrent

<span style="color:#ff0000;">java.util.concurrent.atomic: 对于多线程操作基本数据类型的情况下。可以考虑用此包下的类.</span>
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;


public class Test7 {
	public static void main(String[] args) {
		//线程并发库:java.util.concurrent
		//AtomicInteger:线程安全的对整数操作的类,多个线程访问同一个整数的情况下可以考虑用这类。
		
		//介绍对	基本数据(AtomicIntenger),
		//对数组中的	基本数据(AtomicIntegerArray),
		//对类中的		基本数据的操作(AtomicIntegerFieldUpdater<T>)。
		
		AtomicInteger a = new AtomicInteger(100);
		//如果a(100)==100 ,则a被赋值20,否则返回false。相当与三目运算符
		boolean b = a.compareAndSet(100, 20);
		System.out.println(b);//true
		System.out.println("compareAndSet"+a);//20
		//加1
		int increment = a.incrementAndGet();
		System.out.println("incrementAndGet"+increment);
		//减一
		int decreament = a.decrementAndGet();
		System.out.println("incrementAndGet"+decreament);
		//设置值为60
		a.set(60);
		System.out.println("set"+a);
		//加50(减等于加负数)
		int addresult = a.addAndGet(50);
		System.out.println("addAndGet"+addresult);
		
	}
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值