java 多线程总结

15 篇文章 0 订阅

一、线程的创建

 1.继承Thread类

	class Demo {
			public static void main(String[] args) {
				Thread t = new Thread();
				t.start();                //第三步,调用start()方法
			}
		}
		class MyThread extends Thread {   //第一步,定义类并继承Thread类
			//...定义一些属性或方法
			public  void run() {    //第二步,重写run()方法
				//...
			}
		}

 2.实现Runnable接口

		class Demo {
			public static void main(String[] args) {
				MyThread mt = new MyThread();
				Thread t = new Thread(mt);    //第三步,将Runnable对象传入Thread类的构造函数
				t.start();					  //第四步,调用start()方法
			}
		}
		class MyThread implements Runnable {  //第一步,定义类并实现Runnable接口
			//...定义一些属性或方法
			public void run() {				  //第二步,重写run()方法
				//...
			}
		}
		


 3.匿名内部类的方式简化书写

		class Demo {
			public static void main(String[] args) {
				//第一种方式
				new Thread(){
					//...
					public void run() {
						//...
					}
				}.start();
				
				//第二种方式
				new Thread(new Runnable(){
					//...
					public void run() {
						//...
					}
				}).start();
			}
		}


二、线程常用方法

 1.currentThread : 静态方法,获取当前的线程对象.
 2.getName, setName : 获取和设置线程的名字.
 3.sleep : 静态方法,控制当前线程休眠指定毫秒.
 4.setDaemon : 设置指定线程为守护线程,守护线程不会单独运行.
 5.join : 当前线程暂停,等待指定线程执行完毕后再继续.

		//示例一
		public class ThreadDemo1 {
			public static void main(String[] args) {
				Person p = new Person();
				p.setName("张三");                 //setName()方法.
				p.start();
			}
		}

		class Person extends Thread {
			public void run() {
				for (int i = 0; i < 30; i++) {
					try {
						sleep(400);  //由于继承 了Thread所以可以直接sleep(),而不用Thread.sleep().
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(currentThread().getName()+i);  			                                               }
			}
		}
		
		//示例二 
		public class ThreadDemo {
			public static void main(String[] args) throws InterruptedException {
				Thread t1 = new Thread(){
					public void run() {
						for (int i = 1; i <= 5; i++) {
							System.out.println("A " + i);
							try {
								Thread.sleep(1000);	  //可以直接sleep().		
							} catch(Exception e) {
								e.printStackTrace();	
							}
						}
					}	
				};
		
				Thread t2 = new Thread(){
					public void run() {
						for (int i = 1; i <= 10; i++) {
							System.out.println("B " + i);
							try {
								Thread.sleep(1000);			
							} catch(Exception e) {
								e.printStackTrace();	
							}
						}
					}	
				};
				t2.setDaemon(true);  // 设置t2线程为守护线程,则当t1线程结束后,t2也会结束.
				t1.start();
				t2.start();
			}
		}
		
		//示例三
		public class ThreadDemo {
			public static void main(String[] args) throws InterruptedException {
				final Thread t1 = new Thread(){   //被内部类调用,所以要加final
					public void run() {
						for (int i = 1; i <= 5; i++) {
							System.out.println("A " + i);
							try {
								Thread.sleep(1000);	  //可以直接sleep().		
							} catch(Exception e) {
								e.printStackTrace();	
							}
						}
					}	
				};
		
				Thread t2 = new Thread(){
					public void run() {
						for (int i = 1; i <= 5; i++) {
							System.out.println("B " + i);
							try {
								Thread.sleep(1000);
								if (i == 2)
									t1.join();//当前线程暂停, 等待t1线程执行结束之后再继续		
							} catch(Exception e) {
								e.printStackTrace();	
							}
						}
					}	
				};
				t1.start();
				t2.start();
			}
		}


三 、同步

 1.什么是同步
  在多线程并发访问同一资源时,有可能出现线程安全问题,为了解决这种问提,引出同步技术。
  线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
 2.同步的几种方法
  (1)同步方法
    如果整个方法内的代码都需要同步,可以在方法钱加上synchronized修饰,由于同步方法默认的同步锁是this作为锁对象,
    所以如果需要同步的方法不在同一个类中,则必须改用同步代码块的形式.
  (2)同步代码块
    将需要同步的代码放在 synchronized(){}代码块中,在小括号中指定锁对象.
  
  (3)JDK5中的同步
    使用ReentrantLock类的lock()方法开始同步.
    使用ReentrantLock类的unlock()方法结束同步.
    注意:解锁的代码unlock()方法一定要执行,尽量放在finally.

		//示例一
		class Demo {
			public static void main(String[] args) {
				final Printer p = new Printer(); //匿名内部类调用,需要final修饰
				
				new Thread() {
					public void run() {
						while(true)
							p.print1();
					}
				}.start();
				
				new Thread(new Runnable(){
					public void run() {
						for(;;)                //无限循环
							p.print2();
					}
				}).start();
			}
		}
		class Printer {
			public synchronized void print1() { //同步方法
				System.out.print(1);
				System.out.print(2);
				System.out.println(3);
			}
			public void print2() {
				synchronized(this) {         //同步代码块
					System.out.print("一");
					System.out.print("二");
					System.out.println("三");
				}
			}
		}
		//以上代码如果没有同步,在一行中有可能出现类似 12三或  一2三  等混乱的情况.
		//同步后问题解决.
		
		//示例二
		import java.util.concurrent.locks.ReentrantLock;
		class Demo {
			public static void main(String[] args) {
				final Printer p = new Printer();
				
				new Thread(){
					public void run() {
						while(true) 
							p.print1();
					}
				}.start();
				
				new Thread() {
					public void run() {
						while(true) 
							p.print2();
					}
				}.start();
			}
		}
		class Printer {
			private ReentrantLock lock = new ReentrantLock(); //建立一个用来同步的锁的对象.
			
			public void print1() {
				try {
					lock.lock();           //开始同步
					System.out.print(1);
					System.out.print(2);
					System.out.println(3);
				} finally {
					lock.unlock();		   //结束同步
				}
			}
			
			public void print2() {
				try {
					lock.lock();
					System.out.print("一");
					System.out.print("二");
					System.out.println("三");
				} finally {
					lock.unlock();
				}
			}
		}


四、通信

 如何通信
  首先通信的代码必须写在同步代码中.
  方式一
   使用锁对象来调用wait()和notify().
   wait()方法可以控制当前线程等待,知道其他线程调用notify()或者notifyAll()方法才被唤醒.
  方式二
   先用ReentrantLock调用newCondition()方法获得Condition对象.
   然后使用Condition对象的await()方法等待.
   使用Condition对象的signal()方法唤醒.
   与方式一的区别:可以创建多个Condition对象,不同的线程使用不同的Condition,这样唤醒的时候可以唤醒指定的Condition.

		//示例一
		class Demo {
			public static void main(String[] args) {
				final Printer p = new Printer();
				
				new Thread(){
					public void run() {
						while (true)
							try {
								p.print1();
							} catch(Exception e) {
								e.printStackTrace();
							}
					}
				}.start();
				
				new Thread(){
					public void run() {
						while(true) 
							try {
								p.print2();
							} catch(Exception e) {
								e.printStackTrace();
							}
					}
				}.start();
			}
		}
		class Printer {
			private int flag = 1;     //标记应该轮到哪个方法
			
			public synchronized void print1() throws Exception {
				if (flag == 2)
					wait(); 		 //等待 
				System.out.print(1);
				System.out.print(2);
				System.out.println(3);
				flag = 2;
				notify();		    //通知另一个线程继续
			}
			
			public synchronized void print2() throws Exception {
				if (flag == 1)    
					wait();
				System.out.print("一");
				System.out.print("二");
				System.out.println("三");
				flag = 1;
				notify();				
			}
		}
		
		//示例二
		import java.util.concurrent.locks.ReentrantLock;
		import java.util.concurrent.locks.Condition;
		class Demo {
			public static void main(String[] args) {
				final Printer p = new Printer();
				
				new Thread(){
					public void run() {
						while (true)
							try {
								p.print1();
							} catch(Exception e) {
								e.printStackTrace();
							}
					}
				}.start();
				
				new Thread(){
					public void run() {
						while(true) 
							try {
								p.print2();
							} catch(Exception e) {
								e.printStackTrace();
							}
					}
				}.start();
			}
		}
		class Printer {
			private int flag = 1;     //标记应该轮到哪个方法
			private ReentrantLock lock = new ReentrantLock();
			private Condition c1 = lock.newCondition();
			private Condition c2 = lock.newCondition();
			
			public  void print1() throws Exception {
				try {
					lock.lock(); 
					if (flag == 2)
						c1.await();
					System.out.print(1);
					System.out.print(2);
					System.out.println(3);
					flag = 2;
					c2.signal();
				} finally {
					lock.unlock();
				}
			}
			
			public synchronized void print2() throws Exception {
				try {
					lock.lock(); 
					if (flag == 1)
						c2.await();
					System.out.print("一");
					System.out.print("二");
					System.out.println("三");
					flag = 1;
					c1.signal();
				} finally {
					lock.unlock();
				}
			}
		} 
		//结果是123 一二三交替运行.


五、练习

 1.写一个延迟加载的单例设计模式

		class SingletonDemo {
			public static void main(String[] args) {
				Singleton s1 = Singleton.getInstance();		// 第一次调用时创建对象
				Singleton s2 = Singleton.getInstance();
				System.out.println(s1);
				System.out.println(s2);               //验证一下是否单例,结果两个地址相同.验证成功.
			}
		}
		//延迟加载的,又称为懒汉式
		class Singleton {
			private static Singleton s = null;     
			
			private Singleton(){}
			
			public static synchronized Singleton getInstance() {  
				if (s == null)
					s = new Singleton();
				return s;
			}
			//...   别的属性或者方法
		}
		
		//一般的,称为饿汉式
		class Singleton {
			private static Singleton s = new Singleton(); //2.类内部创建一个对象, 使用成员变量引用. 用static修饰在类加载后初始化. 防止类外修改加上private
			
			private Singleton(){} //1.私有化构造函数,阻止外部创建对象
			
			public static Singleton getInstance() {     //3.提供一个get方法获取对象, 为了让类外直接使用加上static
				return s;
			}
		}

 

 2.写一个买票的示例

		import java.util.concurrent.locks.ReentrantLock;
		class TicketSellerDemo {
			public static void main(String[] args) {
				TicketSeller ts1 = new TicketSeller();
				TicketSeller ts2 = new TicketSeller();
				TicketSeller ts3 = new TicketSeller();
				TicketSeller ts4 = new TicketSeller();
				
				ts1.setName("张三");
				ts2.setName("李四");
				ts3.setName("王五");
				ts4.setName("赵六");
				
				ts1.start();
				ts2.start();
				ts3.start();
				ts4.start();
			}	
		}
		class TicketSeller extends Thread {
			private static int ticket = 100;
			private static ReentrantLock lock = new ReentrantLock();  // 多条线程必须使用同一个锁对象, 才能同步
			
			public void run() {
				while(true)	{ 
					try {
						lock.lock();
						
						if (ticket <= 0)	
							break;
						try {
							Thread.sleep(10);		// 模拟一些耗时的操作
						} catch(Exception e) {
							e.printStackTrace();	
						}
						System.out.println(getName() + " 卖出了第 " + ticket-- + " 号票");
					} finally {
						lock.unlock();
					}
				}
			}
		}
		

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值