1.进程: 正在执行中的程序
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫控制单元。
2.线程:进程中的一个独立的控制单元
线程在控制着进程的执行
每一个进程中至少有一个线程
3.扩展:
a) JAVA VM启动时会有一个进程,叫JAVA .EXE 该进程中至少有一个线程在负责JAVA程序的执行,而且这个线程,运行的代码存在于MAIN方法中。该线程称之为主线程。
b) JVM 启动时不止一个线程,还有负责垃圾回收机制的线程。
4.创建线程的第一种方式 继承THREAD类,覆盖RUN方法 创建该类对象执行START()方法。
a)发现运行结果每一次都不同 因为多个线程都获取cpu 的执行权。CPU执行到谁,谁 就运行。
b)明确一点在同一时刻,只能有一个线程运行。(多核除外)cpu在做着快速的切换以达 到看上去同时运行的效果。
c)我们可以形象地把多线程运行看成是在互相抢夺CPU的资源。多线程的这个特性叫 做随机性。至于执行时间由CPU控制。
5.线程的5种状态
6. 创建线程的第二种方式 RUNABLE接口
a) 定义类,实现RUNABLE接口
b) 覆盖RUNABLE接口中的RUN()方法
c) 通过THREAD类建立线程对象
d) 将RUNABLE的实现对象作为实参传递给Thread的构造函数
e) 调用Thread类的Start()方法开启线程并调用接口子类的Run方法
7.两种方式的区别
实现方式和继承方式的区别
线程代码存放的位置不一样
继承:线程代码存放在T的子类中
实现:线程代码存放在R接口子类中
实现方式避免了单继承的局限性,在定义线程时,建议使用实现方式。
8.多线程的安全问题
a) 无锁的情况下,会出现安全问题
b) 问题的原因: 当多条语句在操作线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程又参与了执行。导致共享数据错误。
c) 解决办法: 对多条操作共享数据的语句,只能让一个线程全部执行完,在执行过程中,其他线程不可以执行。
d) JAVA对于多线程安全问题提供了同步代码块。
synchronized(对象)
{
需要被同步的代码
}
e)代码如下:
public class TicketTest1 implements Runnable
{
private int tick=100;
private int count=0;
Object obj=new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"---"+tick--);
count++;
}
else
{
System.out.println(Thread.currentThread().getName()+"end-----"+count);
break;
}
}
}
}
public static void main(String[] args)
{
TicketTest1 t=new TicketTest1();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
f)对象如同锁,持有锁的线程可以在同步代码块中执行
g)同步的前提
a) 必须要有2个以上的线程才需要同步
b) 必须是多个线程使用同一个锁
必须保证同步当中只有一个线程在运行
h)利弊
i. 利:解决了多线程的安全问题
ii. 弊:多个线程都需要判断锁,较为消耗资源。
i)同步函数使用的锁是THIS,静态同步函数使用的锁是 类名.CLASS 该类的字节码对象
public class LockTest implements Runnable
{
private int tick=1000;
private int count=0;
Object obj=new Object();
boolean flag=true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(this)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"---"+tick--);
count++;
}
else
{
System.out.println(Thread.currentThread().getName()+"end-----"+count);
break;
}
}
}
}
else
{
this.show();
}
}
public synchronized void show()
{
while(true)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"---"+tick--);
count++;
}
else
{
System.out.println(Thread.currentThread().getName()+"end-----"+count);
break;
}
}
}
public static void main(String[] args)
{
LockTest t=new LockTest();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.currentThread().sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
t.flag=false;
t2.start();
}
}
9.单例设计模式
//饿汉式
//class Single
//{
// private static final Single s=new Single();
// private Single()
// {
// }
// public static Single getInstance()
// {
// return s;
// }
//}
//懒汉式 延迟加载 用双重判断减少判断锁的次数
class Single
{
private static Single s=null;
private Single()
{
}
public static Single getInstance()
{
if(null==s)
{
synchronized(Single.class)
{
if(null==s)
{
s=new Single();
}
}
}
return s;
}
}
10.死锁
a)同步中嵌套同步,而锁却不同
b)死锁代码
public class DeadLockTest1
{
public static void main(String[] args)
{
Lock l1=new Lock(true);
Lock l2=new Lock(false);
Thread t1=new Thread(l1);
Thread t2=new Thread(l2);
t1.start();
t2.start();
}
}
class MyLock
{
static Object locka=new Object();
static Object lockb=new Object();
}
class Lock implements Runnable
{
private boolean flag=false;
public Lock(boolean flag)
{
this.flag=flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized(MyLock.locka)
{
System.out.println("if a locked");
synchronized(MyLock.lockb)
{
System.out.println("if b locked");
}
}
}
}
else
{
while(true)
{
synchronized(MyLock.lockb)
{
System.out.println("else b locked");
synchronized(MyLock.locka)
{
System.out.println("else a locked");
}
}
}
}
}
}
11.同步线程间的通信--等待唤醒机制
a)wait() notify() notifyAll() 都使用在同步中,因为要对持有锁的线程操作,而只有同步才会有锁,所以要使用在同步中。
b)上述方法为何要定义在OBJECT中 因为这些方法在操作同步线程时,都必须要标识所操作线程持有的锁,只有同一个锁上的被等待线程可以被同一个锁上的NOTIFY唤醒,不可以对不同锁中的线程进行唤醒。等待和唤醒针对的是同一个锁,而锁可以是任意对象。
c)优化后的通信代码
package com.itheima.thread;
public class InputOutputDemo
{
public static void main(String[] args)
{
Res r=new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
class Res
{
private String name;
private String sex;
private boolean flag;
public synchronized void reset(String name, String sex)
{
if(flag)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
this.name = name;
this.sex = sex;
flag=true;
notify();
}
public synchronized void show()
{
if(!flag)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println(name+"........."+sex);
flag=false;
notify();
}
}
class Input implements Runnable
{
private Res r;
public Input(Res r)
{
this.r=r;
}
public void run()
{
int x=0;
while(true)
{
if(0==x%2)
{
r.reset("tom","male");
}
else
{
r.reset("张三","男男男男男");
}
x++;
}
}
}
class Output implements Runnable
{
private Res r;
public Output(Res r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.show();
}
}
}
d)多个线程通信 WHILE(FLAG) & NITIFYALL(); 防止全部冻结
class Resource
{
private String name;
private int count=1;
private boolean flag=false;
public synchronized void set(String name)
{
while(flag)
{
try
{
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
this.name=name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者... "+this.name);
flag=true;
notifyAll();
}
public synchronized void show()
{
while(!flag)
{
try
{
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...消费者... -----"+this.name);
flag=false;
notifyAll(); //唤醒了全部的等待线程
}
}
e)1.5新特性 (多线程升级解决方案 )
1.SYNCHRONIZED LOCK UNLOCK (显式锁)TIP:一定要释放锁
2.OBJECT WAIT NOTIFY NOTIFYALL CONDITION 通过LOCK获取 可以有 多个CONDITION对象 从而实现本方只唤醒对方的操作
完整代码
package com.itheima.thread1;
public class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource res=new Resource();
new Thread(new Producer(res)).start();
new Thread(new Producer(res)).start();
new Thread(new Consumer(res)).start();
new Thread(new Consumer(res)).start();
}
}
class Resource
{
private String name;
private int count=1;
private boolean flag=false;
public synchronized void set(String name)
{
while(flag)
{
try
{
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
this.name=name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者... "+this.name);
flag=true;
notifyAll();
}
public synchronized void show()
{
while(!flag)
{
try
{
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...消费者... -----"+this.name);
flag=false;
notifyAll();
}
}
class Producer implements Runnable
{
private Resource res;
public Producer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.set("商品");
}
}
}
class Consumer implements Runnable
{
private Resource res;
public Consumer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.show();
}
}
}
12.停止线程
a) STOP方法已经过时 只有一种停止方式 RUN()方法执行完毕
b) 开启多线程,运行代码通常都是循环结构,终止循环即终止了线程
c) 特殊情况: 当线程处于冻结状态,就不会读取到标记,就不会结束
d) Interrput() 中断线程 当进入冻结状态时,消除冻结状态,强制恢复到运行状态
e) 当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结进行消除。强制让线程恢复到运行状态中,从而操作标记让线程结束。
13.setDaemo(boolean on) 后台线程(开启后和前台线程共同运行,当所有前台线程结束后,后台线程会自动结束)
a) 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,JAVA虚拟机将退出。
b) 该方法必须在启动线程前使用
c) 该方法首先调用该线程的checkAccess方法,且不带任何参数。当前线程无法修改时,可能抛出SecurityException
14.join() 等待该线程终止
a) 申请加入到运行中,要CPU执行权
b) 当A线程执行到了B线程的JOIN方法时,A线程在B线程执行完后才执行
c) 可以加入临时线程
15.线程组,很少用,谁开启则属于哪个组
16.优先级 PRIORITY 默认为5 1-10 MAX MIN Thread.NORM_PRIORITY
a) setPriority(int newPriority)
17.yield()
a) 暂停当前线程,并执行其他线程
b) 稍微减少执行的频率,如果有两个线程,达到类似交替执行的效果