java多线程,java多线程教程,java多线程入门使用,定时器和定时任务

一,java多线程的两种创建方式

    1,继承Thread类

        继承Thread类,重写run()方法,run() 里面就是具体线程需要做的事(代码块),然后在主线程main线程中调用start()方法就可以实现线程。

public class TestThread {

	//主线程
	public static void main(String[] args) {		
		
		MyThread t = new MyThread();
		t.start();
		
		
		while (true) {
			System.out.println(Thread.currentThread().getName());
			System.out.println("兔子领先了,别骄傲");
			
		}

	}
	

	
}
	

//线程类
class MyThread extends Thread {			
  @Override
  public void run() {
  	
     	while (true) {
			System.out.println(this.getName());
			System.out.println("乌龟领先了,加油");
		}
     	
  }
	
	}

    2,实现Runnable接口

        可以通过实现Runnable接口来创建线程

public class TestRunnable1 {

	public static void main(String[] args) {
		
		MyThread4 t4=new MyThread4();
		Thread thread=new Thread(t4);
		thread.start();
		
		
		MyThread5 t5=new MyThread5();
		Thread thread1=new Thread(t5);
		thread1.start();
		
		
		while (true) {
			System.out.println(Thread.currentThread().getName());
			System.out.println("兔子领先了,别骄傲");
			
		}
		
		

	}

}




//线程接口的实现类
class MyThread4 implements Runnable {

	@Override
	public void run() {
	
		while (true) {
			System.out.println(Thread.currentThread().getName());
			System.out.println("乌龟领先了,别骄傲");
			
		}
		
	}
	
}


//线程接口的实现类
class MyThread5 implements Runnable {

	@Override
	public void run() {
	
		while (true) {
			System.out.println(Thread.currentThread().getName());
			System.out.println("大象领先了,加油");
			
		}
		
	}
	
}

        也可以通过内部类的方式来创建线程

public class TestRunnable2 {

	public static void main(String[] args) {
		
		Thread thread=new Thread(new Runnable() {
			public void run() {				
				
				while (true) {
					
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					
					System.out.println(Thread.currentThread().getName());
					System.out.println("乌龟领先了,别骄傲");
					
				}
			}
		});
		
		thread.start();
		
		
		
		
		Thread thread1=new Thread(new Runnable() {
			public void run() {			
				
				
				while (true) {
					
					try {
						//Thread.sleep(2000);
						Thread.sleep(4000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					System.out.println(Thread.currentThread().getName());
					System.out.println("大象领先了,加油");
					
				}
			}
		});		
		thread1.start();
		
		
		
		
		
		
		while (true) {
			System.out.println(Thread.currentThread().getName());
			System.out.println("兔子领先了,别骄傲");
			
		}

	}

}

    3,线程常用方法

  •         stop()    强行终止线程,让出cpu资源,但已过期,不推荐使用。
  •         interrupt() 中断线程。
  •         interrupted() 判断当前线程是否中断
  •         isterruoted()  判断当前对象线程是否中断
  •         sleep() 线程休眠,让出CPU资源。
  •         yieid()   与sleep相似,但是不能由用户指定时间,并且yieid()方法只能出让给同优先级的线程机会。
  •         join()    可以让原来并行执行的线程顺序执行,比如在B线程中调用A线程的join()方法,会使B线程等待A线程执行完毕                          后继续执行。
  •        wait() 等待  notify()通知其他线程  notifyAll()通知所有的其他线程。这三个方法会在线程间的通信中具体介绍的。 

二,线程的生命周期

        线程生命周期

三,线程的优先级和同步

        一般来说线程越高的得到的CPU资源就越多,我们虽然说是并发,但是真正执行的程序的只有一个cpu,所以达不到真正的并行,只是我们在使用的时候用户感觉是并行执行的。

     main主线程的优先级是默认的5,其他线程可以手动设置setPriority(),数值为1-10 数字越高,优先级越高。查看优先级可以用getPriority()方法。

        线程的安全问题,多个线程去操作一个共享数据的时候,有可能出现同时操作一个共享数据的情况,这时候就会造成错误,所以为了避免这种错误,我们可以对这个操作加一个同步锁synchronized。

可以在线程调用的方法上加上synchronized关键字,让一个线程调用这个加了同步锁的方法的时候,其他线程不能调用这个方法。

import java.util.Vector;

public class TestSyn1 {

	public static void main(String[] args) {
		
		 //真实角色
    	PlaneBillA web = new PlaneBillA();
    	
        //代理角色
        Thread thread1 = new Thread(web,"农民");
        Thread thread2 = new Thread(web,"工人");
        Thread thread3 = new Thread(web,"学生");
        thread1.start();
        thread2.start();
        thread3.start();
		
		

	}

}





class PlaneBillA implements Runnable{
    private int num=100;//总共10张票
    private boolean flag = true;
    
    
    @Override
    public void run() {
    	
        while(flag){
            //   0  -1
        	//出现重复的票  num=1000设置大一点就出现
        	//线程不安全,数据不准确:结果有-1值,重复值
        	
            function();
            
        }
    }
    
    
    
    //1、线程不安全
    public synchronized void function(){
    	
        if (num<=0) {
            flag = false;
            return;//跳出循环,结束
        }
        
        try {
            Thread.sleep(500);  //模拟延时
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    }
    
    
}

synchronized除了可以用在方法上,还可以用在一段代码段中,作用相同,防止其他的线程来访问,这个过程就叫做线程同步,或者线程互斥。

public class TestSyn2 {

	public static void main(String[] args) {
		
		 //真实角色
    	PlaneBillB web = new PlaneBillB();
    	
        //代理角色
        Thread thread1 = new Thread(web,"农民");
        Thread thread2 = new Thread(web,"工人");
        Thread thread3 = new Thread(web,"学生");
        thread1.start();
        thread2.start();
        thread3.start();
		
		

	}

}





class PlaneBillB implements Runnable{
    private int num=100;//总共10张票
    private boolean flag = true;
    
    
    @Override
    public void run() {
    	
        while(flag){
            //   0  -1
        	//出现重复的票  num=1000设置大一点就出现
        	//线程不安全,数据不准确:结果有-1值,重复值
        	
            function();
            
        }
    }
    
    
    
    //1、线程不安全
    public void function(){
    	String string="hello";
    	
    	//synchronized (this) 
    	synchronized (string)
    	{   		
    		
    		 if (num<=0) {
    	            flag = false;
    	            return;//跳出循环,结束
    	        }
    	        
    	        try {
    	            Thread.sleep(500);  //模拟延时
    	        } catch (InterruptedException e) {
    	            e.printStackTrace();
    	        }
    	        
    	        
    	        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    	    			
		}
    	
    	
    	
    	
    	
       }
    
    
}

 四,线程之间的通信

        线程之间的通信主要依靠同步,但有时候有一些特殊的情况,比如我们常见的生产者,仓库和消费者模型,消费者消费时需要生产者提供生产物到仓库,而生产者生产好了之后要通知消费者。在这里需要用到三个方法,wait(),notify(),notifyall()。

        wait()  中断方法的执行,使本线程等待,暂时出让CPU资源,并允许其他线程使用这个同步方法。

        notify() 唤醒由于使用这个同步方法而进入等待的线程。

        notifyall() 唤醒由于使用这个同步方法而进入等待的所有线程。

 

下面我们以生产者 仓库 消费者模型来举例说明线程之间的通信。

      1 SharedData.java 共享仓库,有生产同步方法 putShareChar 和消费同步方法 getShareChar()。

 

//共享数据类
public class SharedData{
	
	private char c;
	
	private boolean isProduced = false; // 信号量
	
	
	// 同步方法putShareChar()
	public synchronized void putShareChar(char c) {
		// 如果产品还未消费,则生产者等待
		if (isProduced) {
			try{
				System.out.println("消费者还未消费,因此生产者停止生产");
				wait(); // 生产者等待,终止程序
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		this.c = c;
		isProduced = true; // 标记已经生产
		notify(); // 通知消费者已经生产,可以消费
		System.out.println("生产了产品" + c + "  通知消费者消费...");
	}
	
	
	// 同步方法getShareChar()
	public synchronized char getShareChar() {
		// 如果产品还未生产,则消费者等待
		if (!isProduced){
			try{
				System.out.println("生产者还未生产,因此消费者停止消费");
				wait(); // 消费者等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		isProduced = false; // 标记已经消费
		notify(); // 通知需要生产
		System.out.println("消费者消费了产品" + c + "  通知生产者生产...");
		return this.c;
	}
	
	
}

 

        2 Consumer.java 消费者类,它会调用仓库中的同步消费方法 getShareChar()。

//消费者线程
public class Consumer extends Thread {
	
	private SharedData s;
	
	Consumer(SharedData s){
		this.s = s;
		
	}
	
	public void run(){
		
		char ch;
		
		do {
			
			try	{
				Thread.sleep((int) (Math.random() * 3000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			ch = s.getShareChar(); // 从仓库中取出产品
			
		} while (ch != 'D');
		
		
	}
	
	
}

 

        3 Producer.java 生产者类,它会调用同步生产方法 setShareChar()。

//生产者线程
public class Producer extends Thread {

private SharedData s;

	Producer(SharedData s){
		this.s = s;
	}
	
	
	public void run(){
		
		for (char ch = 'A'; ch <= 'D'; ch++){
			
			try{
				Thread.sleep((int) (Math.random() * 3000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			s.putShareChar(ch); // 将产品放入仓库
		}
	}
	
	
}

下面我们初始化这两个线程,让它可以运行起来

public class TestProducerConsumer {

	public static void main(String[] args) {
		
		
		//共享同一个共享资源
		SharedData s = new SharedData();			
		
		//生产者线程
		Producer producer=new Producer(s);
		producer.start();
		
		
		//消费者线程
		Consumer consumer=new Consumer(s);
		consumer.start();

	}

}

从运行的结果可以看出,无论是生产者线程还是消费者线程当共享数据不满足条件时,都会进入wait()方法,同时电泳notify()来通知其他线程执行相关操作,这就是线程之间的通信方法,简单又使用,MQ就是使用了这种方法来提高代码的执行效率。

五 定时任务

        定时器实际上就是一个线程,我们在满足条件的时候调用就可以了。

        定时任务类

import java.util.TimerTask;

public class CustTimeTasker  extends TimerTask{

	@Override
	public void run() {
		
		System.out.println("TimerTask,定时执行任务");
		
	}

}

        调用定时任务

import java.util.Timer;

public class TestTask {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		//定时器
		Timer timer=new Timer();
		
		CustTimeTasker cust=new CustTimeTasker();
		
		//从当前时间开的,10秒后执行一次
		//timer.schedule(cust,1000*10);
		
		//从当前时间开的,3秒后执行  每10秒执行一次,循环执行
		//timer.schedule(cust,3000,1000*10);
		
		
		//从当前时间开的,执行一次
		//timer.schedule(cust, new Date());
		
		
		//从当前时间开的,   每10秒执行一次,循环执行
		timer.schedule(cust, new Date(), 1000*10);
		
	

	}

}

定时任务实际上也属于多线程的内容,所以这里一代而过,关于一些多线程的常用API,可以从这篇文章学习到,如有错误或者理解不深刻的地方,欢迎指出,共同进步。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值