黑马程序员——java多线程的几种实现方法及多窗口售票小程序

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

多线程:   多执行绪,同时执行

进程:实际上可以理解为程序,但有的程序可以有多个进程,操作系统可以同时运行多个进程,这样的操作多进程操作

线程:程序运行的执行路径(执行绪)

JVM是多线程的

实现多线程的方式如下:

思路一:

1.定义线程类继承Tread并重写方法

2.重写run()方法,在run方法中写要执行的程序

3.创建线程类对象

4.启动线程,自动调用方法(用线程对象引用调用start()方法)

代码实现过程如下:

// 定义线程类继承Tread并重写方法
public class MyThread extends Thread{
// 重写run()方法,在run方法中写要执行的程序
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}
public class Test {
// 创建线程类对象
	public static void main(String[] args) {
		
		MyThread thread1 = new MyThread();
		MyThread thread2 = new MyThread();
//		启动线程
		thread1.start();
		thread2.start();
	}
}

此方式还可以使用匿名内部类实现:

public class Test {

	public static void main(String[] args) {
//		用匿名内部类的方式创建线程对象	
		new MyThread().start();
		new MyThread().start();
	}
}
每个线程都有优先级,默认优先级都是5(线程优先级是从1到10的整数)

线程加入:public final void join() throws InterruptedException

使用线程加入的线程,理论上其他线程需要等被加入线程执行完毕后再执行

线程礼让:public static void yield()

暂停当前正在执行的线程对象,并执行其他线程

线程中断:public void interrupt()

中断线程的 wait   join   sleep   相当于唤醒的意思

线程的生命周期:

新建状态:线程被创建,有执行资格

就绪状态:有执行资格,没有cpu使用权

执行状态:有执行资格,有cpu使用权——> 阻塞状态

消亡状态:线程消亡,既没有执行资格,也没有执行权

阻塞状态:sleep()/wait()/IO操作阻塞操作/加锁 ———>就绪状态  唤醒/唤醒/阻塞操作结束/解锁

守护线程:public final void setDaemon()

被守护线程随着守护线程额停止而停止运行


思路二:

1.定义一个类,实现Runnable 接口

2.重写run()方法

3.创建实例对象    在创建线程的对象的时候,传入参数,还可以直接在第二个参数创建名字

4.分配实例对象(创建一个线程对象最为这个线程对象的构造方法参数传入)

5.开启线程


代码实现:

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}
public class Test {

	public static void main(String[] args) {
	//  创建试了对象	
		MyRunnable myRunnable = new MyRunnable();
	//  分配 实例对象	
		Thread thread1 = new Thread(myRunnable);
		Thread thread2 = new Thread(myRunnable);
	//  启动线程	
		thread1.start();
		thread2.start();
	}
}

此方法还可以使用匿名内部类实现:

public class Test {

	public static void main(String[] args) {

//		使用匿名内部类的方式创建线程对象
		new Thread(new MyRunnable(){

			@Override
			public void run() {
				super.run();
				for (int i = 0; i < 10; i++) {
					System.out.println(i);
				}
			}
			
		}).start();   //  开启线程
	}
}


总结:实现runnable接口比继承Thread类好,因为可以在实现接口的同事继承其他的类,而如果继承了Thread类就不能再继承其他的类

这样将run方法中的业务与线程分离

synchronize:同步

使用同步代码块将要同步的代码包裹起来,该代码块需要一个对象作为参数,这个参数是同步代码块的锁由这个锁去判断是否是同一个代码块

锁的创建不能在run()方法内,因为如果放在run方法中,则每个线程都有自己的锁,与其他线程的锁不同,所以锁应该放在成员变量的位置(即在成员位置创建锁的参数对象)


代码实现过程:

1.让共享数据事项runnable接口

2.创建多线程对象,传入相同的共享数据对象

3.开启线程验证


代码实现:

public class Ticket implements Runnable {
	
//	必须要将共享的属性放在成员的位置作为共享数据
	int num = 100;
	Object o = new Object();

	@Override
	public void run() {
		while (true) {
			synchronized (o) {  //此同步代码块不能包括while循环,因为将导致最先获取执行权线程的死循环
				try {
					Thread.sleep(10);  // 让线程睡眠10ms验证数据的同步性
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				if (num > 0) {
					System.out.println(Thread.currentThread().getName()+"正在销售第"+num+"张票");
					num--;
				}
			}
			
		}
	}

}
测试类:

public class Test {

	public static void main(String[] args) {
		
//		创建共享 数据的对象 
		Ticket ticket = new Ticket();
//		创建线程对象
		Thread thread = new Thread(ticket,"窗口1");
		Thread thread2 = new Thread(ticket,"窗口2");
//		开启线程
		thread.start();
		thread2.start();
	}
}

同步方法: 让方法本身同步,使用的锁为调用这个方法的对象this

格式:在方法前加 synchronize 关键字

多个线程跑的都是自己的run()方法,但是共享着run方法中的某些数据

总结:多线程可以保证共享数据的唯一性,可以通过让共享数据的放在成员变量的位置,或者只创建共享数据的一个实例对象来保证数据的唯一性

注意:synchronize 同步代码块只能使用同一个对象才能达到同步的功能



你可能感兴趣的:(java,多线程,同步,synchronize,黑马程序员)