Java学习总结1——多线程编程

Java多线程编程

1、建立线程的方法一:编程

继承:extends Thread 重写run()方法安全

举个栗子🌰:bash

public class MyThread extends Thread {
	public MyThread() {
		//空的构造方法
	}
	
	//传递name表示线程名字
	public MyThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			if (interrupted()) {
				System.out.println("释放资源!");
				break;
			}
			System.out.println(getName()+":"+i);
		}
	}
}
复制代码
MyThread t1 = new MyThread(“线程一”);
MyThread t2 = new MyThread(“线程二”);

Thread thread = new Thread();
thread.start();//启动线程

thread.getPriority();//获取优先级
thread.setPriority();//设置优先级(1-10)

thread .getName();//获取线程名字
thread .setName();//设置线程名字
复制代码

线程休眠:微信

Thread.sleep(4000);//主线程休眠四秒以后再运行
复制代码

线程加入:多线程

t1.join();//将线程t1加入主线程
复制代码

设置守护线程:app

t2.setDaemon(true);将t2线程设置为守护线程(守护线程须要在线程启动以前设置),守护线程是为守护其余线程而存在,若是其余全部线程都运行完以后,只还剩下守护线程没运行完,那么守护线程将自动销毁!ide

线程的中断:ui

t1.interrupt();//手动处理线程中断
interrupted();//将返回布尔值
复制代码

线程的生命周期: this

线程的生命周期


2、建立线程的方法二:spa

实现Runnable接口: implement Runnable

public class RunnableThread implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			Thread thread = Thread.currentThread();//获取当前线程名字
			System.out.println(thread.getName()+":"+i);
		}
		
	}

}
复制代码

该方法不能直接使用start()方法启动线程。 须要使用Thread声明一个对象,再将runnable对象传入Thread对象。

RunnableThread t = new RunnableThread();

Thread t1 = new Thread(t,”线程一”);
t1.start();
		
Thread t2 = new Thread(t,”线程二”);
t2.start();
复制代码

两种建立线程方法区别: runnable方法只须要建立一个runnable对象,Thread方法须要建立多个MyThread对象。Thread方法获取线程其余参数更方便。两种方法都须要重写run()方法。

使用Runnable方法建立线程的好处:

  1. 能够很方便的实现多线程数据的共享。
  2. 该方法还能够继承其余的类,而继承Thread类的方法不能再继承其余的类了。

3、建立线程的方法三:

匿名内部类: 直接在主类里面定义一个Runnable类来实现Runnable接口里面的run()方法。

适用于该线程在主类里面只使用一次的状况,不用再建立一个线程类来实现Runnable接口。

线程安全问题: 当多个线程须要同时修改同一共享数据时,产生冲突,就会出现线程安全问题。

  1. 加锁解决:
private Object lock = new Object();//须要声明一个对象做为锁
复制代码
//加锁
synchronized (lock) {
	//须要加锁执行的代码
}//执行完毕,归还钥匙
复制代码

也能够直接使用同步方法:sellTicket()

public synchronized void sellTicket(){
//须要加锁的代码
}//至关于给这个方法加了锁
复制代码

同步方法不须要再声明一个对象做为锁了。

  1. 使用专门的锁对象ReentrantLock来加锁:
private ReentrantLock lock = new ReentrantLock();
复制代码
lock.lock();//加锁
//须要加锁的代码
lock.unlock();//解锁
复制代码

死锁问题的解决:

多个线程以相同的顺序去取锁,取到全部锁以后才执行须要加锁的代码!

举个栗子🌰:

public class DeadLock {
	//建立两把锁
	public static Object lock1 = new Object();
	public static Object lock2 = new Object();
	
	public static void main(String[] args) {
		//启动两个线程
		new Thread(new Thread1()).start();
		new Thread(new Thread2()).start();
	}
}

//匿名内部类实现Runnable建立Thread1线程
class Thread1 implements Runnable{
	
	@Override
	public void run() {
		synchronized (DeadLock.lock1) {//先取第一把锁
			System.out.println("Thread1取得了第一把锁以后要作的事情");
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized (DeadLock.lock2) {//再取第二把锁
				System.out.println("Thread1同时取得两把锁以后要作的事情");
			}
		}
	}
	
}

//匿名内部类实现Runnable建立Thread2线程
class Thread2 implements Runnable{

	@Override
	public void run() {
		synchronized (DeadLock.lock1) {//先取第一把锁
			System.out.println("Thread2取得了第二把锁以后要作的事情");
			synchronized (DeadLock.lock2) {//再取第二把锁
				System.out.println("Thread2同时取得两把锁以后要作的事情");
			}
		}
	}
	
}
复制代码

建立线程组:ThreadGroup

ThreadGroup tg = new ThreadGroup(“个人线程组”);
复制代码

定时器:Timer

须要在计时器任务里面设置任务:TimerTask

Timer timer = new Timer();//定时器
timer.schedule(new MyTimer(), 2000);//2s后启动计时器任务
timer.schedule(new MyTimer(), 2000, 1000);//2s启动后,隔3s后再重复执行计时器任务
timer.cancel();//取消定时器
复制代码

举个栗子🌰:

public class Demo_Timer {
	public static void main(String[] args) {
		Timer timer = new Timer();//定时器
		
		//timer.schedule(new MyTimer(), 2000);
		timer.schedule(new MyTimer(), 2000, 1000);
		//timer.cancel();//取消定时器
		
	}
}

//定时器任务(匿名内部类)
class MyTimer extends TimerTask{

	@Override
	public void run() {
		System.out.println("定时器任务..");
	}
		
}
复制代码

4、综合实例:

电影院售票问题: 说明:两种买票方式,手机APP端和电影院窗口端同时售票,采用建立多线程的方式来解决电影票多端售出产生的冲突!

采用实现Runnable接口的方法建立线程。

一、建立AppThread类:(APP端线程类)

public class AppThread implements Runnable {
	private Object lock;
	
	public AppThread(Object lock) {
		this.lock = lock;
	}
	
	@Override
	public void run() {
		while (MovieTicketManage.count>0) {
			synchronized (lock) {
				if (MovieTicketManage.count>0) {
					System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"张电影票..");
					MovieTicketManage.count--;
				}
			}
			
			try {
				Thread.sleep(0);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

}
复制代码

二、建立WindowThread类:(window端线程类)

public class WindowThread implements Runnable {
	private Object lock;
	
	public WindowThread(Object lock) {
		this.lock = lock;
	}
	
	@Override
	public void run() {
		while (MovieTicketManage.count>0) {
			synchronized (lock) {
				if (MovieTicketManage.count>0) {
					System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"张电影票..");
					MovieTicketManage.count--;
				}
			}
			
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}

	}

}
复制代码

三、建立MovieTicketManage类:(票管理类,存储电影票数量,为了多线程数据的共享)

public class MovieTicketManage {
	public static int count = 100;
}
复制代码

四、建立CinemaSale主类:(电影票售票主类)

public class CinemaSale {
	public static void main(String[] args) {
		Object lock = new Object();
		
		WindowThread windowThread = new WindowThread(lock);
		AppThread appThread = new AppThread(lock);
		
		new Thread(windowThread,"窗口").start();
		new Thread(appThread,"APP手机").start(); 
	}
}
复制代码

须要建立一把相同的锁lock,将这把锁传入AppThread和WindowThread线程类,保证锁的惟一,若是在AppThread线程和WindowThread线程里面建立锁,那么就是不一样对象的锁了。就不能保证共享数据的同步,经过定义一个成员变量lock,经过构造方法将这个锁传递过来.

这样在购买电影票的时候就不会产生线程冲突和死锁问题了!😁

今日寄语:

去作那些让你紧张的事情,当你克服了这段焦虑以后,你会发现,一切没你想象的那么困难。💪

欢迎关注我的微信公众号:桃李报春

相关文章
相关标签/搜索