多线程创建以及解决数据同步问题


今日重点:
1.掌握线程的两种创建方式及其区别
2.掌握解决线程安全的同步代码块及同步方法
3.掌握线程的常用方法
4.理解线程的生命周期
5.理解线程安全问题的产生原因及其解决方法

一,复习

1.程序,进程与线程的区别

程序:是为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象

进程:是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生,存在和消亡的过程
																	———————生命周期
																	
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。 	
若一个进程同一时间并行执行多个线程,就是支持多线程的。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程切换的开销小
一个进程中多个线程共享相同的内存单元,但是同时也会带来一定的安全隐患。

2.并行与并发的区别


并行:多个CPU执行多个任务;比如:多个人同时做不同的事。
并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀,多个人做同一件事。


并发看似多个任务同时进行,其实是多个任务在短暂的时间片内进行切换
并行是真正意义上的一同执行。


并行与并发的区别:

①并行是指多个事件在同一时刻发生,而并发是指多个事务在某一个时间间隔内发生。
②并行是不同实体上的多个事件,并发是同一实体上的不同事件
③并行是在多台处理器上处理多个任务,并发是在一台处理器上处理多件事情

二,线程的创建(两种传统的方式)

1.方式一:继承Thread类

步骤:
1.创建Thread类的子类
2.重写Thread类中的run()方法;将当前线程要执行的操作声明在run()内
3.实例化Thread的子类
4.通过Thread类的子类对象调用其start():①启动线程②调用当前线程的run()


说明
①如果通过Thread类的子类对象调用run()方法,则不能够实现多线程操作,只能算是一次方法的重写,多线程的启动必须调用start()方法
②每个对象的start()只能调用一次,多次调用会报IllegalThreadStateException

练习:

public class ThreadTest {
	public static void main(String[] args) {
		
//		EvenNumber evenNumber = new EvenNumber();
//		evenNumber.start();
		
		OddNumber oddNumber = new OddNumber();
		oddNumber.start();
		
		
	}

}


class OddNumber extends Thread{//奇数
	public void run() {
		
		for(int i = 0;i <= 100;i++) {
			if(i%2!=0) {
				System.out.println(Thread.currentThread().getName()+"**"+i);
			}
		}
		
	}

}

2.方式二:实现Runnable接口


步骤:

1.创建实现Runnable接口的子类,重写run()方法。
2.创建实现Runnable接口的子类对象
3.创建Thread类的实例对象,并将Runnable接口的子类对象放在其构造方法中
4.通过Thread类的实例对象调用start()


练习

public class ThreadTest2 {

	public static void main(String[] args) {

		windows1 w = new windows1();

		Thread t1 = new Thread(w, "窗口1");
		Thread t2 = new Thread(w, "窗口2");
		Thread t3 = new Thread(w, "窗口3");

		t1.start();
		t2.start();
		t3.start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				for(int i = 1;i <= 100;i++) {
					if(i%2!=0) {
						System.out.println(Thread.currentThread().getName()+"**"+i);
					}
					if(i%20==0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					
					
				}
				
			}

		},"打印奇数!!").start();

	}

}

class windows1 implements Runnable {
	private int ticket = 1000;

	@Override
	public void run() {
		while (true) {
			if (ticket > 0) {
				System.out.println(Thread.currentThread().getName() + "票号为:"
						+ ticket);
				ticket--;
				if(ticket==200) {
					try {
						Thread.currentThread().join();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			} else {
				break;
			}
		}

	}

}

3.两种方式的对比


 *  相同点:都需要进行方法的重写(run());启动线程都需要调用Thread类的start()
 *  对比:① 类可以实现多个接口;但是只能继承一个父类 ② 实现的方式更方便的来处理有共享数据的情况
 *  结论:实现Runnable的方式要好于继承Thread的方式
 *  联系:public class Thread implements Runnable

三,线程常用的方法

start()
run()
currentThread()
getName()
setName()
sleep(long milisecond)://一旦执行该方法,线程阻塞milisecond毫秒次
yield():每当执行此方法时,线程主动释放cpu执行权。
join():在线程A中调用线程B的方法,线程A进入阻塞状态,直到线程B执行完成后,线程A不再是阻塞状态,开始正常执行。
isAlive():判断当前线程是否存活
线程优先级
①优先级的等级:
MIN_PRIORITY = 1
NORM_PRIORITY = 5 默认优先级
MAX_PRIORITY = 10

②如何设置优先级
getPriority():
setPriority(int priority)://设置

③调度策略
高优先级要抢占低优先级的策略
高优先级的策略只是从概率上面来讲,并不是一定能够抢占成功

四,线程的生命周期

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6W9KPn8-1584062778899)(C:\Users\xxxxxx\AppData\Roaming\Typora\typora-user-images\1583840248496.png)]

五,线程的同步

1.同步机制,用于解决线程安全问题

 * 例题:开启三个窗口售票,总票数为100张。使用Runnable接口实现类的方式实现
 * 
 * 1. 出现的问题:出现了重票和错票  ---> 即为线程安全问题
 * 2. 出现的原因:由于一个线程在操作ticket尚未操作完的情况下,其他线程参与进来继续操作ticket,导致出现了重票和错票。
 * 3. 如何解决? 必须保证一个线程操作ticket,在完成操作完的时候,其他线程才能参与进行继续操作ticket.
 * 
 * 4. Java是如何实现的?使用同步机制,解决线程的安全问题

2.方式一:同步代码块


方式一:

synchronized(同步监视器){
    //需要被同步的代码
}

说明:①需要被同步的代码,即为共享数据的代码,要求:包裹共享数据的代码,不能包多了,也不能包少了
	 ②何为共享数据?多个线程共同操作的数据。比如ticket
	 ③同步监视器:俗称锁,可以为任意类型的一个类的对象。
	 	要求:多个线程,必须共用同一个监视器
	 ④同步监视器可以考虑用this,也可以用当前类.class

同步代码块解决实现Runnable接口多线程不同步问题

public class SynchronizedTest {
	public static void main(String[] args) {
		windows w = new windows();

		Thread t1 = new Thread(w, "窗口1");
		Thread t2 = new Thread(w, "窗口2");
		Thread t3 = new Thread(w, "窗口3");
		
		new Thread(new Runnable() {	
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println(111);
			}
		}).start();
		
		t1.start();
		t2.start();
		t3.start();

	}
}

class windows implements Runnable {
	private int ticket = 100;

	@Override
	public void run() {

		while (true) {
			synchronized (this) {
				if (ticket > 0) {

//					try {
//						Thread.sleep(30);
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}

					System.out.println(Thread.currentThread().getName()
							+ "票号为:" + ticket);
					ticket--;
				} else {
					break;
				}
			}

		}

	}
}

同步代码块解决继承Thread类的问题

public class SynchrnoizedThreadTest {

	public static void main(String[] args) {
		
		desk d1 = new desk();
		desk d2 = new desk();
		desk d3 = new desk();
		
		d1.start();
		d2.start();
		d3.start();
		
		
	}

}

class desk extends Thread {

	private static int ticket = 100;

	@Override
	public void run() {

		while (true) {
			synchronized (desk.class) {
				if (ticket > 0) {

					// try {
					// Thread.sleep(30);
					// } catch (InterruptedException e) {
					// // TODO Auto-generated catch block
					// e.printStackTrace();
					// }

					System.out.println(Thread.currentThread().getName()
							+ "票号为:" + ticket);
					ticket--;
				} else {
					break;
				}
			}

		}

	}

}

3.方式二:同步方法

使用同步方法解决通过实现Runnable完成多线程中遇到的线程不同步问题


public class SynchrnoizedMethoedTest {

	public static void main(String[] args) {
		move m1 = new move();
		Thread t1 = new Thread(m1);
		Thread t2 = new Thread(m1);
		Thread t3 = new Thread(m1);
		
		t1.start();
		t2.start();
		t3.start();
	}
	
}

class move implements Runnable {
	private int ticket = 100;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (; ticket > 0;) {
			show();
		}

	}

	private synchronized void show() {

		if (ticket > 0) {

			 try {
			 Thread.sleep(30);
			 } catch (InterruptedException e) {
			 // TODO Auto-generated catch block
			 e.printStackTrace();
			 }

			System.out.println(Thread.currentThread().getName() + "票号为:"
					+ ticket);
			ticket--;
		}
	}

}

使用同步方法解决通过继承Thread类完成多线程中遇到的线程不同步问题

public class SynchrnoizedMethoedTest2 {

	public static void main(String[] args) {
		
		desk1 d1 = new desk1();
		desk1 d2 = new desk1();
		desk1 d3 = new desk1();
		
		d1.start();
		d2.start();
		d3.start();
		
	}
	
}

class desk1 extends Thread {

	private static int ticket = 100;

	@Override
	public void run() {

		for (; ticket > 0;) {
			show();
		}

	}
	
	private static synchronized void show() {
		if (ticket > 0) {

			 try {
			 Thread.sleep(30);
			 } catch (InterruptedException e) {
			 // TODO Auto-generated catch block
			 e.printStackTrace();
			 }

			System.out.println(Thread.currentThread().getName()
					+ "票号为:" + ticket);
			ticket--;
		} 
	}
	

}

();
desk1 d3 = new desk1();

	d1.start();
	d2.start();
	d3.start();
	
}

}

class desk1 extends Thread {

private static int ticket = 100;

@Override
public void run() {

	for (; ticket > 0;) {
		show();
	}

}

private static synchronized void show() {
	if (ticket > 0) {

		 try {
		 Thread.sleep(30);
		 } catch (InterruptedException e) {
		 // TODO Auto-generated catch block
		 e.printStackTrace();
		 }

		System.out.println(Thread.currentThread().getName()
				+ "票号为:" + ticket);
		ticket--;
	} 
}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值