------- android培训、java培训、期待与您交流! ----------
进程:就是一个正在执行中的程序。每个进程都有一个执行顺序,叫一个执行路径,或一个控制单元。
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。
Java VM 启动时会有一个进程java.exe
进程中至少有一个线程在负责程序的执行,并且运行的代码存在于main方法中,称之为主线程。
其实启动时还有个垃圾回收机制的线程。
多线程的特性:随机性,谁抢到执行权,谁执行。
Thread类中的run方法是用于存储要执行的代码,要覆盖。
使用方法:
一:继承Thread类
1,定义类继承Thread.
2,复写Thread类中的run方法
目的为了把自定义的代码存储到run方法中,并让线程运行。
3,调用线程的start方法。作用(启动线程,调用run方法)。
二:创建线程的第二种方式,实现Runnable接口。
步骤:
1,定义类实现Runnable接口
2,覆盖Runnable接口中的run方法(将线程要运行的代码存放在该run方法中)
3,通过Thread类建立线程对象
4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数(因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,必须要明确该run方法所属的对象)
5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
继承和实现的区别
实现方式避免了单继承的局限性,建议使用实现方式。
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable,线程代码存放在接口子类的run方法中。
线程的4种状态
创建 start() 运行 sleep(time)时间到会自动运行;wait()等待notify()唤醒
冻结(睡眠和等待两种)
消亡 stop();或run方法结束。
特殊状态 :临时状态,阻塞 有运行资格CPU没有给执行权。冻结没有运行资格,结束冻结会先回到临时状态。
多线程中,由于阻塞状态,多条语句操作同一个线程共享数据时,可能一个线程正在执行时产生阻塞,另一个线程也参与执行。导致出现安全隐患。
如何找到安全隐患
1,明确多线程运行的代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的。
解决办法是,对多线程执行共享数据的语句,只能让一个线程执行完。过程中不准别的参与。加锁。
Java提供了专业解决方式。
就是同步代码块
同步函数
函数要被对象调用,就会有个所属对象引用,就是this,锁是 this.
静态同步函数被类调用,直接属于类,锁是 类名.class,类型是Class。
synchronized做为修饰符。
修饰符 修饰符 返回值类型 函数名()
死锁
同步中嵌套同步,用的锁不相同,就会产生死锁。
synchronized(对象)//相当于一次只能完全执行一个线程,过程中不能执行其他线程。
{
需要被同步的代码
}
前提:
1,必须要有两个或者多个以上的线程。
2,必须是多个线程使用同一个共享数据。
必须保证共同使用的共享数据要同步,就是只执行一个线程。
解决了多线程的安全问题,但是由于需要判断,较消耗资源。
static Thread curretThread():获取当前线程对象。
getName():获取线程名称。
setName或者是构造函数可以用来设置线程名称。
class Demo extends Thread//继承Thread
{
//复写Thread类中的run方法
public void run()
{
//自定义要线程运行的代码
for(int x=1;x<10;x++)
System.out.println("Demo run_"+x);
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo();//创建好一个线程d.
//d.start();//开启d线程,并且执行其中的run方法。
d.run();//只是调用了run方法,线程却没有运行,只创建了。
for(int x=1;x<10;x++)
System.out.println("main run_"+x);
}
}
//卖票程序:多个窗口买票
class Ticket implements Runnable//实现Runnable接口 同步代码块
{
private int tick = 100;
Object obj = new Object();
public void run()//将线程要运行的代码存放在该run方法中
{
while(true)
{
synchronized(obj)//同步代码块
{
//多线程执行共享数据的语句
if(tick>0)//由于临时状态,阻塞,多线程可能出现安全隐患
{
System.out.println(Thread.currentThread().getName()+"..."+ tick--);
}
}
}
}
}
class Ticket implements Runnable//实现Runnable接口 同步函数
{
private int tick = 100;
public void run()
{
while(true)
{
this.show();
}
}
//由于临时状态,阻塞,多线程可能出现安全隐患
public synchronized void show()//同步函数synchronized(this)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"..."+ tick--);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();//建立Runnable接口的子类对象
Thread t1 = new Thread(t);//Thread类建立线程对象,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.start();//调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
t2.start();
t3.start();
}
}
等待唤醒机制
wait();线程等待
notify();唤醒其他线程
notifyAll();唤醒全部线程
都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要用在同步中,只有同步才有锁。
因为这些方法在操作同步线程时,都必须要标识它们所操作的线程共有的锁,只有同一锁上的被等待线程,可以被同一个锁上notify唤醒。不同锁的线程不能进行唤醒。就是只能于相同锁上才有效。
锁可以是任意对象,因此能被任意对象调用的方法只能定义在Object类中。
if()notify()用于一对一线程。用于多对多时可能会覆盖
while()notifyAll()用于多对多线程。while不用All会全部冻结。
JDK1.5中提供了多线程升级解决方案。将同步Synchronized替换成实现Lock操作。将Object中的wait,notify notifyAll,替换成了Condition对象,该对象可以Lock锁,进行获取。
可以唤醒不同锁。相当于父类引用指向子类对象,多态的方法调用一样。能够唤醒指定的锁。
停止线程
stop方法过时,只能run方法结束。
开启多线程运行,运行代码通常是循环结构。控制住循环,就能让run结束,关闭线程。
当线程处于冻结状态时,不会读到结束,不会结束线程。
没有指定方式让冻结的线程恢复到运行状态时,需要清除冻结状态,强制让线程恢复到运行状态中,就可以操作线程让线程结束。
Thread类中提供了interrupt();方法。
守护线程
setDaemon
public final void setDaemon(boolean on)
t1.setDaemon(true);
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。就是守护线程不能独立运行。
Join
public final void join()
throws InterruptedException
等待该线程终止。
就是借用正在执行线程的执行权,结束了才交还执行线程。
用于临时加入线程。
yield
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
相当于放弃下执行权,不长期占用。
toString
public String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。一般谁开的线程就属于哪个组。
setPriority
public final void setPriority(int newPriority)更改线程的优先级。 (1到10分为1,5,10三等)
线程间通讯
多个线程操作同一个资源,操作动作不同(输入输出)。
class Res//要共用的资源
{
private String name;
private String sex;
private boolean flag = false;//用来改变线程状态
public synchronized void set(String name,String sex)
{
if(flag) //b函数上锁是this
try{this.wait();}catch(Exception e){}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(Exception e){}
//wait()有异常,实现接口中只能try
System.out.println(name+"---"+sex);
flag = false;
this.notify();//唤醒线程
}
}
//输入操作线程
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;//定义输入值
while(true)
{
if(x==0)
r.set("mini","man");
else
r.set("一一","女");
x = (x+1)%2;
}
}
}
//输出操作线程
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
class InputOutputDemo
{
public static void main(String[] args)
{
//建立共用操作对象
Res r = new Res();
//使用匿名对象开启线程
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
------- android培训 、 java培训 、期待与您交流! ----------