JAVA自学课程笔记8

本文详细讲解了Java中`synchronized`关键字的使用,包括代码块锁的原理、火车买票问题的演示、生产和消费问题的同步栈实现,以及如何避免并发问题。通过实例解析,理解了线程同步如何确保同一资源的互斥访问。
摘要由CSDN通过智能技术生成
2021322021分
JAVA自学课程笔记8synchronized(同步)修饰代码块:
		格式:
			synchronized(object aa){
				//同步代码块
			}

		含义:判断aa是否已经被其他线程霸占(术语:锁定),如果发现已经被其他线程霸占。则当前线程陷入等待中,如果发现aa没有被其他线程霸占,则当前线程霸占在aa对象,并执行语句内的同步代码块在当前线程执行同步代码块代码时,其他线程将无法再执行同步代码块的代码(因为当前线程已经霸占了aa对象),当前线程执行完同步代码块的代码后,会自动释放对aa对象的霸占,此时其他线程会相互竞争对aa的霸占,最终CPU会选择其中的某个线程执行。霸占住的那个对象术语叫:监听器。

		最终导致的结果是:一个线程正在操作某资源的时候,将不允许其它线程操作该资源,即一次只允许一个线程处理该资源。

		火车买票程序:
			Test1:
				class A implements Runnable{
					public static int tickets = 100;

					public void run(){
						while(true){
							if(tickets > 0){
								System.out.printf("%s线程正在卖出第%d张票", Thread.currentThread().getName(), tickets);
								tickets --;
							}else{
								break;
							}
						}
					}
				}

				public class Test1{
					public static void main(String[] args){
						A aa1 =  new A();
						Thread t1 = new Thread(aa1);
						t1.start();

						A aa2 = new A();
						Thread t2 = new Thread(aa2);
						t2.start();
					}
				}
			//虽然用的是static修饰的tickets,但是还是会在执行语句时发生落差,一个对象在不同线程被同时执行且产生时间差,例如1号线程在卖第99张票时,2号线程已经在卖第94张票了,假如正好下一次轮到了1号线程卖,就卖到了第93张。同一个对象被两个线程同时占用,应发程序bug。
				
			Test2:
				class A implements Runnable{
					public static int tickets = 100;
					String str = new String("我是一个字符对象!");

					public void run(){
						while(true){
							synchronized(str){
								if(tickets > 0){
									System.out.printf("%s线程正在卖出第%d张票\n", Thread.currentThread().getName(), tickets);

									tickets --;
								}else{
									break;
								}
							}
						}
					}
				}

				public class Test2{
					public static void main(String[] args){
						A aa = new A();
						Thread t1 = new Thread(aa);
						t1.start();

						Thread t2 = new Thread(aa);
						t2.start();
					}
				}


			synchronized修饰一个方法时,实际霸占的是该方法的this指针所指的对象(即synchronized修饰一个方法时,实际霸占的是正在调用该方法的对象)当一个线程进入这个方法后,这个方法的大门就会暂时关闭(不许其他线程进入)直到这个线程走出这个方法后,该方法的大门才会敞开。当然,这个关闭只是对于该类的当前实例有效,多个实例的对象仍然可以同时执行。若Test2run()方法用synchronized修饰,运行结果会是永远只有一个线程在卖票。
	

	生产和消费程序:
		class SynStack{
			private int cnt =  0;
			private char[] data = new char[6];

			public synchronized void push(char c){
				while(cnt==data.length){
					try{
						this.wait();
					}catch(InterruptedException e){}
				}
				this.notify();

				data[cnt] = c;
				cnt++;
				System.out.println("produced    #: "+c);
			}

			public synchronized char pop(){
				char c;

				while(cnt==0){
					try{
						this.wait();
					}catch(InterruptedException e){}
				}
				this.notify();
				cnt--;
				System.out.println("consumed    *: "+data[cnt]);
				return data[cnt];
			}
		}


		class Producer implements Runnable{
			private SynStack ss = null;

			public Producer(SynStack ss){
				this.ss = ss;
			}
			
			public void run(){
				char c;

				for(int i=0; i<20; ++i){
					c = (char)('1'+i);
					ss.push(c);
				}
			}
		}


		class Consumer implements Runnable{
			private SynStack ss = null;

			public Consumer(SynStack ss){
				this.ss = ss;
			}

			public void run(){
				for(int i=0; i<20; ++i){
					try{
						Thread.sleep(2000);
					}catch(InterruptedException e){}

					ss.pop();
				}
			}
		}


		public class test1{
			public static void main(String[] args){
				SynStack ss = new SynStack();
				Producer p = new Producer(ss);
				Consumer c = new Consumer(ss);
				Thread t1 = new Thread(p);
				t1.start();

				Thread t2 = new Thread(c);
				t2.start();
			}
		}
	//满足一个线程消费,另外一个线程生产且具有同步性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值