黑马程序员 Java基础 多线程技术

要了解多线程,就要先了解线程和进程。

进程是指每个独立程序在计算机上的一次执行活动,例如运行的QQ,电影播放器等,运行一个程序就是启动一个进程。

线程是比进程更小的执行单位,基于线程的多任务处理就是一个程序可以执行多个任务,比如迅雷从网上下载一段视频,用户可以在下载完成前就可以播放已下载的内容,这是因为有两个线程,一个下载,一个播放。

线程和进程的区别

1、每个进程都有独立的代码和数据空间,进程间的切换开销大。

2、同一个进程内的多个线程共享相同的代码和数据空间,每个线程有独立的运行栈和程序计数器,线程间切换开销小。

所以,通常在以下情况可能要用到多线程:

1、程序需要同时执行两个或多个任务。

2、程序需要实现一些需要等待的任务,如用户输入、文件读写操作、网络操作等。

3、需要一些后台运行的程序时。


1、线程的创建与启动

java的线程需要通过Thread类来实现。

1)Thread类里有一个run()方法,线程运行的代码都是封装在run()里面,所以run()也称为线程体。

2)通过Thread对象的start()方法来调用这个线程。

除了Thread里的run()方法,我们也可以通过实现Runnable接口的run()方法往线程添加线程体。

<pre name="code" class="java">public class StrTest {

	public static void main(String[] args) {
		//线程一
		Thread thread1=new MyThread();
		//线程二
		Thread thread2=new Thread(new MyRunnable());
               
		//启动线程一
		thread1.start();
		//启动线程二
		thread2.start();
		
		
		
	}

}
//方法一
class MyThread extends Thread{
	public void run(){
            
		System.out.println("这是线程体");
	}
}
// 方法二
class MyRunnable implements Runnable{
	public void run(){
               
		System.out.println("这是runnable线程体");
	}
}

 
需要注意的是单核CPU里的Jvm在执行多线程时不是同步进行的,它是在多个线程里来回切换,在某一个时刻,jvm只再运行一个线程,切换的时间非常短,一般看不出来,若以看起来就好像多个线程在同时执行。 

这里不得不有个疑问,既然Cpu只能做一个时刻执行一个线程,为什么还需要多线程呢?

因为多线程程序作为一种多任务并发的工作方式,具有以下优点:

1、改善应用程序的响应。当一个操作耗时很长,整个系统都会等这个操作,就不能执行其他操作,而多线程将耗时较长的操作放到一个新线程执行,其他操作也可以得到执行,加强用户体验。

2、提高计算机CPU的利用率。

3、改善程序结构。


2、线程的分类

java中线程分两类:一种叫守护线程,另一种叫用户线程。上面的例子都是用户线程。那么什么是守护线程呢?守护线程是一种”在后台提供通用性支持“的线程,它不属于程序本体。

那么如何判断哪个线程是守护线程,哪个是用户线程。

其实用户线程和守护线程基本是没有区别的,唯一的区别是判断虚拟机什么时候离开。

1、用户线程:java虚拟机在它所有非守护线程都已经离开后自动离开。

2、守护线程:守护线程是用来服务用户线程的,如果没有其他用户线程在运行,守护线程才离开。

这部分不怎么好理解,其实用户线程就可以简单的理解成你需要运行的代码,而守护线程就是当运行这些代码时,你需要的一个环境,例如jvm里的垃圾回收器就是一个典型的守护线程。

public class StrTest {

	public static void main(String[] args) {
		//线程一
		Thread thread1=new MyThread();
		//线程二
		Thread thread2=new Thread(new MyRunnable());
                //把线程二设置为守护线程
                thread2.setDaemon(true);
		//启动线程一
		thread1.start();
		//启动线程二
		thread2.start();
		
		
		
	}

}
//方法一
class MyThread extends Thread{
	public void run(){
            for(int x=1;x<10;x++)
		System.out.println("这是线程体");
	}
}
// 方法二
class MyRunnable implements Runnable{
	public void run(){
                for(int x=1;x<10000;x++)
		System.out.println("这是runnable线程体");
	}
}
把上面例子改了一下,把thread2设置为守护线程,由于线程2的循环次数远大于线程一的循环次数,按道理来说线程2要打印10000 次这是runnable线程体,可是结果就是在线程一打完没多久线程2也结束了,所以上面的守护线程也不难理解了 。


3、线程的状态

线程的状态分成开始、可运行、阻塞、时间等待、等待唤醒、结束

4、线程的同步

当两个或多个线程需要共享对同一个数据的访问,如果每个线程都会调用修改数据的方法,那么这些线程就会互相影响对方,从而影响运行的结果。

为什么会这样呢?

前文提过,多线程的执行是跟jvm根据 cpu所分配的时间片来运行的,线程间是来回切换的而且线程都有独立的运算栈,所以共享数据修改容易发生错误。

这时候,我们就需要对多线程共享数据操作进行同步。

同步有两种方法,一个是synchronized(){}代码块,一个是同步函数。每一种方法里面都需要一个对象锁。

等待唤醒机制是同步的一个重要组成部分,当调用同步代码时,可以加上wait()方法让线程暂停,并放弃对象锁。notify()方法用来唤醒线程。

下面是一个同步等待唤醒的一个经典模型,是模拟产品生产销售的例子。

public class ProducerConsumerDemo1 {

        public static void main(String[] args) {
                Resource1 r = new Resource1();
                 Producer1 p =new  Producer1(r);
                 Consumer1 c=new Consumer1(r);
                 
                 Thread t1 = new Thread(p);
                 Thread t2 = new Thread(p);
                 Thread t3 = new Thread(c);
                 Thread t4 = new Thread(c);
                 t1.start();
                 t2.start();
                 t3.start();
                 t4.start();

        }

}


class Resource1{
        private String name;
        private int count=1;
        private boolean flag = false;
        private Lock lock = new ReentrantLock();
        private Condition con_pro = lock.newCondition();
        private Condition con_con = lock.newCondition();
        public  void set(String name)throws InterruptedException{
                lock.lock();
                try {
                while(flag) {
                        
                                con_pro.await();
                        
                }
                this.name=name+"--"+count++;
                System.out.println(Thread.currentThread().getName()+"生产者..."+this.name);
                flag=true;
                con_con.signal();
                }
                
                finally{
                        lock.unlock();
                }
                
        }
        public  void out() throws InterruptedException{
                lock.lock();
                try{
                while(!flag) {
                        
                  con_con.await();
                }
                System.out.println(Thread.currentThread().getName()+"消费者........."+this.name);
                 flag =false;
                con_pro.signal();
                }
                
                finally{
                        lock.unlock();
                }
        }
}


class Producer1 implements Runnable{
         private Resource1 res;
         Producer1(Resource1 res){
                 this.res=res;
                 
         }
         public void run(){
                 while(true){
                         try {
                                res.set("商品");
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                 }
         }
}


class Consumer1 implements Runnable{
        private  Resource1 res;
        Consumer1(Resource1 res){
                this.res=res;
        }
        public void run(){
                while(true){
                        try {
                                res.out();
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                }
        }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值