您的位置:首页 > 编程语言 > Java开发

Java学习笔记-多线程

2015-02-14 01:01 363 查看
-----------android培训java培训、java学习型技术博客、期待与您交流!------------ 
 

进程:正在执行中的一个程序。

线程:是一个正在执行的程序,进程中一个独立的控制单元。线程控制着进程的执行。

多线程:多线程的出现能让程序产生同时运行效果。可以提高程序执行效率。

线程状态:创建状态--->运行状态--->临时状态(具备执行资格,但没有执行权)----->冻结状态(放弃执行资格,进入临时状态)------>消亡状态。

创建线程方法:

1.继承Thread类,覆写run方法。

代码示例:

package ThreadDemo;

public class ThreadTest {
public static void main(String [] args){
Demo d = new Demo();//创建Demo对象,因为Demo继承了Thread所以创建Demo对象也是创建了一个线程。
d.start();//start方法启动线程,并调用run方法
for(int i=0;i<60;i++){
System.out.println("main....run"+i);
}
}
}
class Demo extends Thread{//继承Thread类;
@Override
public void run(){//覆写run方法,run方法里存放线程执行的代码。
for(int x=0;x<60;x++){
System.out.println("demo....run"+x);
}
}
}


注意:启动线程必须用start方法,如果直接调用run方法,该线程并没有启动,相当于单线程,程序会按顺序执行。

2.实现Runnable,覆写run方法。

(1)已经有了Thread类为什么还要有Runnable接口:继承只能是单继承,如果一个类已经继承了其他类但是还有代码需要多线程执行,这时就没办法再继承Thread类(单继承Java不允许多继承,但可以通过实现接口,扩展功能)

(2)实现Runnable接口和继承Thread类的区别:

实现Runnable的好处:避免了继承的局限性。资源可以共享

继承Thread类线程代码存放在Thread子类的run方法中。

实现Runnable接口线程代码存放在接口子类的run方法中。

代码示例:

package ThreadDemo;

public class ThreadTest1 {
public static void main(String [] args){
TicketDemo td= new TicketDemo();
new Thread(td).start();//创建线程,接受一个Runnable接口的子类,并启动线程
new Thread(td).start();
new Thread(td).start();
new Thread(td).start();
}
}
class TicketDemo implements Runnable{//实现Runnable接口
private int ticket=100;
@Override
public void run(){//覆写run方法。
while(true){
if(ticket>0)
System.out.println(Thread.currentThread().getName()+"...sale"+ticket--);
}
}
}

3.多线程安全:

当多线程操作共享数据时(多条语句),一个线程执行了一部分的语句,还没执行完,另一个线程参与执行,这样就会导致数据错乱,会出现安全问题。

同步可以解决多线程的安全问题:加同步后一个线程执行的时候会先拿到锁,当只执行完后以后会释放锁,下一个线程拿到锁才可以执行同步内的代码。

同步的前提:

(1)必须要有两个或两个以上的线程,

(2)必须多个线程使用同一个锁。

同步好处:解决线程的安全问题。

同步弊端:多线程需要判断锁,较为消耗资源。

同步代码块:自己需要指定一个锁。

代码示例:

Object obj = new Object();
private int sum=0;
public void add(int n){
synchronized(obj){
sum=sum+n;
System.out.println(sum);
}
}


同步函数:使用本类对象的锁(this)

private int sum=0;
public synchronized void  add(int n){
sum=sum+n;
System.out.println(sum);
}


静态同步函数:使用的是所在类的字节码文件对象(类名.class)

class bank{
private static int sum=0;
public static synchronized void  add(int n){
sum=sum+n;
System.out.println(sum);
}
}


4.线程间的通信:安全问题

注意:两个线程同时操作一个资源,对资源来说就是多线程,所以两个函数里的代码都需要同步,而且必须得用同一个锁。

package Thread;
public class InputOutpuDemo {
public static void main(String [] args){
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();//创建线程传入存入的对象,启动线程。
new Thread(out).start();
}
}
class Res{//共享资源
String name;
String sex;
boolean flag;
}
class Input implements Runnable{//实现runnable接口
private Res r;
Input(Res r){//定义构造函数接收共享资源
this.r=r;
}
@Override
public void run(){//覆写run方法
int x=0;
while(true){
synchronized(r){//构造代码块使用的是共同资源对象
if(x==0){
r.name="mike";
r.sex="man";
}
else{
r.name="丽丽";
r.sex="女女女女";
}
x=(x+1)%2;//切换存入数据
}
}
}
}
class Output implements Runnable{//实现runnable接口
private Res r;
Output(Res r){//接收共同资源
this.r=r;
}
@Override
public void run(){//覆写run方法
while(true){
synchronized(r){//同步代码块,跟存入的代码都需要同步,使用同一个锁
System.out.println(r.name+"..."+r.sex);
}
}
}
}

5.等待唤醒机制:wait,notify;

注意:这里只有两个线程,每次唤醒都是对方。代码可以优化,在资源里设置赋值方法和取出方法,同步赋值和取出方法,同时实现等待唤醒机制,再线程代码里直接调用这两个方法就可以

package Thread;

public class InputOutpuDemo {
public static void main(String [] args){
Res r = new Res();//创建资源对象
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();//创建线程,并启动线程
new Thread(out).start();
}
}
class Res{
String name;
String sex;
boolean flag;//定义标记达到存一次取一次的目的,不会乱
}
class Input implements Runnable{//实现runnable接口
private Res r;
Input(Res r){//构造函数接收共享资源
this.r=r;
}
@Override
public void run(){//覆写run方法
int x=0;
while(true){
synchronized(r){//同步代码块,解决程序的安全问题
if(r.flag)//flag默认为flase,条件为假,跳过wait向下执行
try {
wait();//会抛异常需要处理
} catch (InterruptedException e) {
e.printStackTrace();
}
if(x==0){//定义条件循环添加元素
r.name="mike";//给共享资源属性赋值,也就是存入数据
r.sex="man";
}
else{
r.name="丽丽";
r.sex="女女女女";
}
x=(x+1)%2;
r.flag=true;//执行一次将条件改为true,让线程等待,等待前唤醒线程池里的线程
notify();
}
}
}
}
class Output implements Runnable{//实现runnable接口
private Res r;
Output(Res r){//构造函数接收共享资源
this.r=r;
}
@Override
public void run(){//覆写run方法
while(true){
synchronized(r){//同步代码块
if(!r.flag)//条件为假(flase)等待,上一个线程已经讲条件改为true,跳过等待向下执行
try {
wait();
} catch (InterruptedException e) {//处理异常
e.printStackTrace();
}
System.out.println(r.name+"..."+r.sex);
r.flag=false;//执行完更改条件让线程等待,等待前唤醒线程池里的线程。
notify();
}
}
}
}
<strong>6.JDK1.5以后出现了Condition接口。替代了Object的wait(),notify,notifyAll();</strong>

await()
signal()
signalAll()

Lock替代了synchronized;更好的解决了唤醒对方的问题。

解决了线程的唤醒不能唤醒对方的问题。

代码示例:

package ThreadDemo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadLock {
public static void main(String [] args){
Stroage st =new Stroage();
new Thread(new Input1(st)).start();//创建线程,
new Thread(new Input1(st)).start();
new Thread(new Input1(st)).start();
new Thread(new Output1(st)).start();
new Thread(new Output1(st)).start();
new Thread(new Output1(st)).start();
}
}
class Stroage{
private int [] cells=new int [10];//定义数组,存储元素
private int inpos,outpos;//定义角标
private boolean flag;
private Lock lock = new ReentrantLock();//创建锁对象,lock是接口只能用子类创建对象
private Condition condition_in=lock.newCondition();//创建两个condition对象,condition是接口可以用lock.newCondition创建,一个用于存入一个用于输出,这样可以只唤醒对方线程。
private Condition condition_out=lock.newCondition();
public  void put(int num){//定义存数据的方法
lock.lock();//获取所
while(flag)
try {
condition_in.await();//condition等待方法替代了Object的wait方法,本方等待。
} catch (InterruptedException e) {
e.printStackTrace();
}
cells[inpos]=num++;
System.out.println("在clles["+inpos+"]中存入数据--"+cells[inpos]);
inpos++;
if(inpos==cells.length)
inpos=0;
flag=true;
condition_out.signal();//唤醒对方线程;
lock.unlock();//释放锁。
}

public  void out(){//定义取出数据的方法。
lock.lock();//获取锁
while(!flag)
try {
condition_out.await();//本方等待,
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("从cells["+outpos+"]中取出数据"+cells[outpos]);
outpos++;
if(outpos==cells.length)
outpos=0;
flag=false;
condition_in.signal();//唤醒对方线程
lock.unlock();//释放锁
}

}
class Input1 implements Runnable{//实现Runnable接口
private Stroage st;
private int num;
Input1(Stroage st){
this.st=st;
}
@Override
public void run(){//覆写run方法
while(true){
st.put(num++);
}
}
}
class Output1 implements Runnable{//实现Runnable接口
private Stroage st;
Output1(Stroage st){
this.st=st;
}
@Override
public void run(){//覆写run方法
while(true){
st.out();
}
}
}

7.中断线程,interrupt()

线程处于中断状态而又无法被唤醒时,interrupt可以强制清除中断状态。但会抛异常。

8.守护线程:setDeamon()

线程启动前标记为守护线程,当前台没有线程是,守护线程会自动结束。

9.join

特点:当A线程执行到了B线程的join方法时,A线程就会等待,等B线程运行结束后,A线程才会运行。

join可以临时加入线程执行。

10.线程优先级

setPriority()设置线程优先级,默认都是5,只有1-10.  MAX_PRIORITY(10)    MIN_PRIORITY(1)   NORM_PRIORITY(5).

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

-----------android培训java培训、java学习型技术博客、期待与您交流!------------
 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 thread