一、程序、进程、线程 三者关系与区别
程序:静态的,一堆数据与语句的集合,也就是平时写的代码。
进程:动态的,程序运行的一次过程,也就是运行该程序。
线程:
相当于是执行进程的多个路线,进程中的main函数就是主线程,如果没有多线程,进程就只能按照程序中的代码老老实实的按照顺序执行,当在main函数中调用其他函数时,只能先中断,保存上下文去先执行要调用的函数,才能回到main函数原位置继续执行代码。
如果是多线程,当调用其他函数时,单独开辟一个线程去执行该函数,不影响main函数的执行,main函数继续执行,这两个线程同时执行。是CPU决定哪一个线程先执行,其实并不是多个线程同时被CPU调用执行,只是CPU执行速度快,给人感觉是并发执行线程的。
二、Java中创建线程的方法3种:Thread、Runnable、Callable
1、Thread类 继承Thread类 (Thread类本身就是实现Runnable接口的)
2、Runnable接口 实现Runnable接口
3、Callable接口 实现Callable接口
(一)、extends继承Thread类
创建线程方法:
A、将一个类声明为Thread子类
B、重写run()方法
C、主函数main中该 类 new一个对象开启start()新线程
代码实现:
(二)implements实现Runnable接口
(优点:推荐使用该方法,灵活方便,方便同一个对象被多个线程使用,多个线程可以执行同一个对象,如火车票例子、龟兔赛跑例子)
龟兔赛跑中:多个线程分别指乌龟和兔子,而对象指实现Runnable接口的赛道对象,两个线程都在赛道对象中执行。
创建线程方法:
不同点:创建Runnable接口线程对象,然后把对象丢入Thread 类调用start()方法!!!
代码实现:
但是当多个线程调用同一个对象时会产生严重的资源数据不同步问题。
如以下火车票例子,抢到了相同的票:
package com; public class TestThread1 implements Runnable{ private int ticketNums = 10; @Override public void run() { while (true){ if (ticketNums<0){ break; } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"票"); } } public static void main(String[] args) { TestThread1 ticket = new TestThread1(); //两个参数:第一个是线程对象,第二个是线程名字 new Thread(ticket,"小米").start(); new Thread(ticket,"花花").start(); new Thread(ticket,"妞妞").start(); } }
(三)implements实现Callable接口
new一个线程对象t1
创建一个服务ser
使用服务来提交线程对象t1,开始执行该线程即call()函数体
可以获取返回结果
关闭服务ser
三、线程同步(synchronized)
多个线程操作同一个资源(并发)
解决办法:队列++++锁
同步方法:加上关键字synchronized设置(隐式锁)、或者设置ReentrantLock可重复锁(显示锁)
锁的对象有两种:
synchronized方法、synchronized块(锁的是要变化的量)
synchronized方法 :把buy()方法锁住
package com; public class TestThread1 implements Runnable{ private int ticketNums = 10; boolean flag = true; @Override public void run() { while (flag) { buy(); } } //synchronized给buy()方法设置为同步方法,设置一把锁, //只有前一个人买完票,才把buy()方法给下一个人 public synchronized void buy(){ if (ticketNums<=0) { flag=false; return; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "票"); } public static void main(String[] args) { TestThread1 ticket = new TestThread1(); new Thread(ticket,"小米").start(); new Thread(ticket,"花花").start(); new Thread(ticket,"妞妞").start(); } }