JavaSE基础学习笔记-多线程

进程:是一个正在被执行的程序,每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫做控制单元,用于表示内存总的空间。

线程:是一个进程中的一个独立的控制单元,线程在控制着进程是执行。


如何定义一个线程?

Java提供对线程的描述:Thread

创建线程的第一种方式:让自定义的类继承Thread类,并重写当中的run方法

创建线程的第二种方式:实现Runnable接口,重写run方法。


虽然这两种方式都可以创建一个线程,但是推荐用第二种方式,因为Java不支持多继承,这样用继承Thread类的方式会有很大的局限性,而Runnable接口为线程类提供了一个规则,吧线程的特性定义成了一种功能供自定义线程类进行扩展使用,同时用第二种方法把线程代码封装到自己的类中,而不是线程当中,这样程序是扩展性就很好,而第一种方式是吧线程代码封装到了线程内部,局限性比较大。


为什么要重写run方法呢?

因为run方法中封装了线程要执行的代码。而父类Thread或Runnable接口中的run方法的没有具体实现的,所以子类要自定义run方法中要执行的内容。


如何启动线程?

当线程类是继承自Thread类时,用该类对象调用父类的start()方法即可启动线程。

当线程类是实现Runnable接口时,吧该类的对象作为参数传递给Thread对象,并用此Thread对象调用start()方法启动线程。


线程的安全问题

由于系统运行时,CPU对数据的处理是用时间片的方式来进行的,也就是说CPU在各个程序之间进行着快所的切换处理,这就导致了在多线程程序中,一个线程在执行过程中很容易被剥夺执行权而去执行另外一个线程,这时如果两个线程是操作同一个代码块就会出现数据不一致的情况,这种情况对于大数据高并发的程序非常危险。

要解决这个问题,要么要求CPU一直执行一个线程,结束以后再运行其他线程,要么就让一个线程来执行代码库,该线程不执行完毕其他线程不能执行,也就是线程同步。

显然第一种方式是不可能做到的,那么就得用第二种方法来解决。

Java中提供了两种方式来实现这样的功能:第一种是将要被同步处理的代码用一个同步代码块来封装,第二总是将要被同步处理的代码块所在的方法用synchronized关键性修饰,使其具有同步性。

第一种方式的具体格式为:

synchronized(Object obj){

      代码块;

}

其中obj为任意对象。

第二中方式的具体格式为:

synchronized  返回值   方法名(){

    代码块;

]

第二中同步方式中,当该方法为非静态是,默认同步锁为当前对象,即this,当该方法为静态是,默认同步锁为该类的class字节码文件对象。



线程间的通信:

例子:多生产者-多消费者    第一种方式

/**
 * 多生产者-多消费者
 * 生产者生产一个,消费者消费一个,
 * 
 * */
class Source{
	private String name;
	private int count;
	boolean flag = false;
	public void setDate(String name){
		//同步处理,否则出现数据不一致
		synchronized (Object.class) {
			while(flag){       //多生产者   消费者 用while + notifyAll():唤醒所有线程。
				               //如果是一共生产者一个消费者可以用if + notify()
				try {
					Object.class.wait();   //线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//生产
			this.name = name;
			System.out.println(Thread.currentThread().getName() + "NO."
					+ count++ + "ProductName:" + name);
			flag = true; //改变标记
			Object.class.notifyAll();  //唤醒消费者所以线程
		}
	}
	public void consume(){
		synchronized(Object.class){
			while(!flag){
				try{
					//线程等待
					Object.class.wait();
				}catch(Exception e){}
			}
			System.out.println(Thread.currentThread().getName() + "NO." + (count-1) + "Name:" + name);
			flag = false; //改变标记
			Object.class.notifyAll();  //唤醒生产者线程
			
		}
	}
}
/**
 * 定义生产者线程
 * */
class Producer implements Runnable{
   private 	Source s;
   public Producer(Source s){
	   this.s = s;
   }
	public void run(){
	    while(true){
	    	s.setDate("商品");
	    }
	}
}
/**
 * 定义消费者线程
 * */
class Consumer implements Runnable{
	private Source s;
	public Consumer(Source s){
		this.s = s;
	}
	public void run(){
		while(true){
			s.consume();
		}
	}
}

public class ThreadDemoSeven {
     public static void main(String []args){
    	 Source s = new Source();
    	 Producer p = new Producer(s);
    	 Consumer c = new Consumer(s);
    	 //创建两个生产线程,两个消费线程
    	 Thread t1 = new Thread(p,"Producer");
    	 Thread t2 = new Thread(p,"Producer");
    	 Thread t3 = new Thread(c,"Consumer");
    	 Thread t4 = new Thread(c,"Consumer");
    	 //启动线程
    	 t1.start();
    	 t2.start();
    	 t3.start();
    	 t4.start();
     }
}

第二张方式:运用jdk1.5提供的Lock类,可以更灵活的实现线程通信

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Sources{
	private String name;
	private int count;
	boolean flag = false;
	//定义一个线程锁
	private Lock lock = new ReentrantLock();
	//一个锁上可以有多个Condition进行标记
	private Condition condition_pro = lock.newCondition();  //生产线程锁
	private Condition condition_con = lock.newCondition();  //消费线程锁
	public void setDate(String name) throws InterruptedException{
		  //加锁
		lock.lock();
		try {
			while (flag) {
				//让生产线程进入等待
				condition_pro.await();
			}
			this.name = name;
			System.out.println(Thread.currentThread().getName() + "NO."
					+ count++ + "ProductName:" + name);
			flag = true; //改变标记
			condition_con.signal();  //唤醒消费线程
		} finally {
			lock.unlock();
		}
	}
	public void consume() throws InterruptedException{
		//加锁
		lock.lock();
		try {
			while (!flag) {
				condition_con.await();  //消费线程进入等待
			}
			System.out.println(Thread.currentThread().getName() + "NO."
					+ (count - 1) + "Name:" + name);
			flag = false;
			//唤醒生产线程
			condition_pro.signalAll();
		} finally {
			lock.unlock();
		}
	}
}
/**
 * 定义线程类
 * */
class Producers implements Runnable{
   private 	Source s;
   public Producers(Source s){
	   this.s = s;
   }
	public void run(){
		try {
			while (true) {
				s.setDate("商品");
			}
		} catch (Exception e) {
		}
	}
}

class Consumers implements Runnable{
	private Source s;
	public Consumers(Source s){
		this.s = s;
	}
	public void run(){
		try {
			while (true) {
				s.consume();
			}
		} catch (Exception e) {
		}
	}
}
/**
 * 测试类
 * */
public class LokeDemoOne {
       public static void main(String []args){
    	   Source s = new Source();
      	 Producer p = new Producer(s);
      	 Consumer c = new Consumer(s);
      	 //四个线程,两个消费线程,两个生产线程
      	 Thread t1 = new Thread(p,"Producer");
      	 Thread t2 = new Thread(p,"Producer");
      	 Thread t3 = new Thread(c,"Consumer");
      	 Thread t4 = new Thread(c,"Consumer");
      	 //启动
      	 t1.start();
      	 t2.start();
      	 t3.start();
      	 t4.start();
       }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值