多线程

目录

一、创建线程的两种方式

1.继承Thread类

2.  实现Runnable接口

【区别】

【实现方法的好处】

二、Thread类的有关方法

三、线程的生命周期

四、线程的同步

前提:

解决方式:

方式一:同步代码块:

方式二:同步方法:将操作共享数据的方法声明为synchronized

五、线程的通信


一、创建线程的两种方式

1.继承Thread

 1)  定义子类继承Thread类。

 2)  子类中重写Thread类中的run方法。

 3创建Thread子类对象,即创建了线程对象。

 4调用线程对象start方法:启动线程,调用run方法。

//方式一:继承于Thread类
class PrintNum extends Thread{
	public void run(){
		//子线程执行的代码
		for(int i = 1;i <= 100;i++){
			if(i % 2 == 0){
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}
	}
	public PrintNum(String name){
		super(name);
	}
}


public class TestThread {
	public static void main(String[] args) {
		PrintNum p1 = new PrintNum("线程1");
		PrintNum p2 = new PrintNum("线程2");
		p1.setPriority(Thread.MAX_PRIORITY);//10
		p2.setPriority(Thread.MIN_PRIORITY);//1
		p1.start();
		p2.start();
	}
}

2.  实现Runnable接口

1定义子类,实现Runnable接口。

2子类中重写Runnable接口中的run方法。

3)通过Thread类含参构造器创建线程对象。

4Runnable接口的子类对象作为实际参数传递

      Thread类的构造方法中。

5)调用Thread类的start方法:开启线程,调用

      Runnable子类接口的run方法

//方式二:实现Runnable接口
class SubThread implements Runnable{
	public void run(){
		//子线程执行的代码
		for(int i = 1;i <= 100;i++){
			if(i % 2 == 0){
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}			
	}
}
public class TestThread{
	public static void main(String[] args){
		SubThread s = new SubThread();
		Thread t1 = new Thread(s);
		Thread t2 = new Thread(s);
		
		t1.setName("线程1");
		t2.setName("线程2");
		
		t1.start();
		t2.start();
	}
}

区别

继承Thread:       线程代码存放Thread子类run方法中。

实现Runnable:线程代码存在接口的子类的run方法。

实现方法的好处

1)避免了单继承的局限性

2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。

二、Thread类的有关方法

void start():  启动线程,并执行对象的run()方法

run():  线程在被调度时执行的操作

String getName():  返回线程的名称

void setName(String name):设置该线程名称

static currentThread(): 返回当前线程

static  void  yield()线程让步

Ø暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程

Ø队列中没有同优先级的线程,忽略此方法

join()当某个程序执行流中调用其他线程的 join() 方法时,调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止  

低优先级的线程也可以获得执行

static  void  sleep(long millis)(指定时间:毫秒)

Ø令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。

stop(): 强制线程生命期结束

boolean isAlive():返回boolean,判断线程是否还活着

getPriority() 返回线程优先值

setPriority(int newPriority) 改变线程的优先级,线程创建时继承父线程的优先级

三、线程的生命周期

新建: 一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

就绪:处于新建状态的线程start(),将进入线程队列等待CPU时间片,此时它已具备了运行的条件

运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()方法定义了线程的操作和功能

阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 临时中止自己的执行,进入阻塞状态

死亡:线程完成了它的全部工作或线程被提前强制性地中止  

四、线程的同步

前提:

      如果我们创建的多个线程,存在着共享数据,那么就有可能出现线程的安全问题:当其中一个线程操作共享数据时,还未操作完成,另外的线程就参与进来,导致对共享数据的操作出现问题。

解决方式:

       要求一个线程操作共享数据时,只有当其完成操作完成共享数据,其它线程才有机会执行共享数据。

方式一:同步代码块:

        synchronized(同步监视器){
            //操作共享数据的代码
        }
    注: 1.同步监视器:俗称锁,任何一个类的对象都可以才充当锁。要想保证线程的安全,必须要求所有的线程共用同一把锁!
            2.使用实现Runnable接口的方式创建多线程的话,同步代码块中的锁,可以考虑是this。如果使用继承Thread类的方式,慎用this!
            3.共享数据:多个线程需要共同操作的变量。   明确哪部分是操作共享数据的代码。

方式二:同步方法:将操作共享数据的方法声明为synchronized

比如:public synchronized void show(){ //操作共享数据的代码}
    注:1.对于非静态的方法而言,使用同步的话,默认锁为:this。如果使用在继承的方式实现多线程的话,慎用!
           2.对于静态的方法,如果使用同步,默认的锁为:当前类本身。以单例的懒汉式为例。 Class clazz = Singleton.class        
总结:释放锁:wait();
           不释放锁: sleep()   yield()  suspend() (过时,可能导致死锁)

死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
死锁是我们在使用同步时,需要避免的问题!
 

class Account {
	double money;

	public synchronized void changeMoney(double change) {
		this.money += change;
		// 放大线程安全问题
//		try {
//			Thread.sleep(10);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		System.out.println(Thread.currentThread().getName() + ":" + money);
	}

}

class Custom {

	Account account;

	public Custom(Account account) {
		super();
		this.account = account;
	}

	public void saveMoney() {
		new Thread() {
			public void run() {
				for (int i = 0; i < 3; i++) {
					account.changeMoney(1000);
				}
			};
		}.start();
	}
}

/**
 * 银行有一个账户。有两个储户分别向同一个账户存3000元, 每次存1000,存3次。每次存完打印账户余额。
 * 
 * @author Administrator
 */

public class TestThread {
	public static void main(String[] args) {
		Account account = new Account();
		Custom cust1 = new Custom(account);
		Custom cust2 = new Custom(account);

		cust1.saveMoney();
		cust2.saveMoney();

	}
}

五、线程的通信

如下的三个方法必须使用在同步代码块或同步方法中!
wait():当在同步中,执行到此方法,则此线程“等待”,直至其他线程执行notify()的方法,将其唤醒,唤醒后继续其wait()后的代码
notify()/notifyAll():在同步中,执行到此方法,则唤醒其他的某一个或所有的被wait的线程。
>例题:1.两个线程交替打印1-100自然数   2.生产者、消费者的例子

class Clerk {
	int capacity;

	public synchronized void addCapacity() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(capacity >= 20) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else {
			capacity++;			
			System.out.println(Thread.currentThread().getName()+":"+"生产了第"+capacity+"个产品");
			notifyAll();
		}
		
	}

	public synchronized void subCapacity() {	
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(capacity <= 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else {
			System.out.println(Thread.currentThread().getName()+":"+"消费了第"+capacity+"个产品");
			capacity--;
			notifyAll();
		}		
	}
}

class Product implements Runnable {

	Clerk clerk;

	public Product(Clerk clerk) {
		super();
		this.clerk = clerk;
	}

	// 生产
	@Override
	public void run() {
		while(true) {
			clerk.addCapacity();
		}
	}

}

class Custom implements Runnable {
	Clerk clerk;

	public Custom(Clerk clerk) {
		super();
		this.clerk = clerk;
	}

	// 消费
	@Override
	public void run() {
		while(true) {
			clerk.subCapacity();
		}
	}
}

public class ProductAndCustom {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Clerk clerk = new Clerk();
		Product product = new Product(clerk);
		Custom custom = new Custom(clerk);
		Thread t1 = new Thread(product);
		Thread t2 = new Thread(custom);
		t1.setName("生产者1");
		t2.setName("消费者1");
		t1.start();
		t2.start();
		
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值