学习笔记--多线程_概述

摘要

首先记录线程的基本概念,然后记录如何实现线程,接着记录多线程中的同步问题,最后记录如何实现多线程之间的通讯和停止线程。


1.基本概念

 进程:正在运行的程序

 线程:线程是进程的执行路径或者说是控制单元,每个进程中至少有一个线程

2.实现线程的方式

i.继承Thread类重写run方法,代码如下:

class DemoThread extends Thread{

	@Override
	public void run() {
	//线程要执行的代码放在此处
	}	
}
启动线程代码:

DemoThread dt = new DemoThread();
dt.start();


ii.实现Runnable接口,代码如下:

class DemoRunnable implements Runnable{

	@Override
	public void run() {
		//线程要执行的代码放在此处
		
	}
启动线程依赖于Thread对象,启动方式如下:

DemoRunable dr = new DemoRunable ();
Thread t = new Thread(dr);
t.start();

iii.通过线程池实现线程,代码如下:

Executors.newSingleThreadExecutor().execute(new Runnable() {
			@Override
			public void run() {
				//线程要执行的代码放在此处
			}
		});
继承Thread和Runnable实现的区别:

继承Thread类则无法再继承其他类,扩展性降低,然后Thread对象本身代表一个线程无法启动多个线程

实现Runnable接口时可以继承其他类扩展性好,可以通过多Thread对象启动多个线程

3.线程安全问题(线程同步)

当多个线程对同一资源进行操作时,可能导致线程安全问题。例如经典的消费者和生产者问题。

解决线程安全的方式有如下:

i.同步代码块

将操作公共资源的代码放在同步代码块当中,代码如下:

synchronized (obj) {
					//需要同步的代码
				}

ii.同步方法,代码如下:

public synchronized void method(){
		
	}
iii.使用本身具有线程安全特性的集合例如HashTable 、Vector

iv. 使用java.concurrent.lock

注意使用同步锁来保证线程安全时需要保证使用的同步锁对象是同一个对象


4.线程间通讯

在多线程之间往往需要进程之间进行通讯,例如在生产者和消费者之间需要需要在生产者生产之后才可以进行消费,只能消费一次,消费一次之后需要生产者再次生产。

实现通讯的方法有:

i.wait();//线程冻结,只有唤醒之后才再次执行

ii.nofity();//唤醒某一锁下的等待线程

iii.notifyAll();//唤醒某一锁下的全部等待线程

demo代码如下:

public class IntOut {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Person p = new Person();
		Thread in = new Thread(new Input(p));
		Thread out = new Thread(new Output(p));
		in.start();
		out.start();
	}

}
class Person{
	private String name;
	private String sex;
	private boolean flag = false;
	
	public Person(){
		name="静候";
		sex="女";
	}
	public void set(String name,String sex){
		this.name = name;
		this.sex = sex;
	}
	public void out(){
		System.out.println(this.name+"    "+this.sex);
	}
	public boolean getFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	
}
class Input implements Runnable{

	private Person p = null;
	public Input(Person p){
		this.p = p;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int i =0;
		while(true){
			synchronized (p) {
				if(Input.this.p.getFlag()){
					try {
						p.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if(i%2==0){
					Input.this.p.set("佳音", "女");
				}else{
					Input.this.p.set("静候", "男");
				}
				i = (i+1)%2;
				p.setFlag(true);
				p.notify();
			}
		}
	}
	
	
}
class Output implements Runnable{

	private Person p = null;
	public Output(Person p){
		this.p = p;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			synchronized (p) {
				if(!p.getFlag()){
					try {
						p.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				Output.this.p.out();
				p.setFlag(false);
				p.notify();
			}
			
		}
	}
	
	
}

5.停止线程

以往的停止线程的方法有stop,但已经过时是不安全的,停止线程的最合适的方法时run方法执行结束,而run方法中往往是存在循环,只要控制循环条件便可以停止线程。

但是有些线程被挂起冻结,则这些线程无法访问到循环控制条件则无法停止线程,可以通过interrupt方法强制使线程进入运行状态。demo代码如下:

public class StopThread implements Runnable{

	/**
	 * @param args
	 */
	private boolean flag = true;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		StopThread st = new StopThread();
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		t1.start();
		t2.start();
		int count = 0;
		while(true){
			if((count++)>90){
				st.setFlag();
				t1.interrupt();
				t2.interrupt();
				break;
			}else{
				System.out.println("main"+count);
			}
		}
	}

	@Override
	public/* synchronized */void run() {
		// TODO Auto-generated method stub
		while(flag){
			try{
				
					//wait();
				
			}catch(/*Interrupted*/Exception e){
				System.out.println("in exception");
				flag = false;
			}
			System.out.println("in"+Thread.currentThread().getName());
		}
	}
	public void setFlag(){
		this.flag = false;
	}
	
}

总结

这篇日记记录了线程的基本内容,但没有详细的记录线程间通讯的问题(多生产者多消费者的问题)和使用lock实现锁的功能,及Executor的使用,右面有其他日记描述。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值