一  引言 :

           进程是一个正在执行中的程序,每个进程执行都有一个执行顺序,或执行路径;

           线程是进程中的内容,是进程中独立的控制单元;

           线程控制着进程的执行,或者是一个控制单元;

           一个进程中至少有一个线程;


二  如何创建线程

1.第一种方式为:


将类声明为Thread的子类,该子类应重写Thread类的run方法

例如:


class TestChildThread extends Thread{


@Override
public void run() {
super.run();
}
}


创建好子线程后,我们接下来启动使用它

class Test { 

public static void main(String[] args) {

//创建线程
TestChildThread d = new TestChildThread();
//启动
d . start();

}}



 2. 第二种方式是实现 Runnable接口,并重写Thread的run方法



class  RunnableDemo implements Runnable{
@Override
public void run() {
}
}

class TestRunnableClass{
public static void main(String[] args)
{
RunnableDemo runnableDemo = new RunnableDemo();
Thread t = new Thread(runnableDemo);
t . start();
}
}




注:  1. 定义类实现Runable接口来创建线程

         2. 覆盖 Runable 中run方法,将要执行的代码放入;

         3. 通过 Thread 类建立线和对象 

         4.将 Runnable接口子类对象作为实际参数传递给Thread类的构造函数中

         5.调用 Thread类的 start  方法 开户线程 

 注: 两种创建线程方式的区别:

        实现方式的好处,了单继承的局限性

       在定义线程时,建议使用实现类

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

       实现Runable,线程将代码存放在接口的子类run方法中


3.注  :  在某一个时刻,只能有一个程序在运行;

              在多线程中,有一个特性:随机执行;

              d . run();是调用类Demo类中的run方法,而未启动线程


      4.为什么要重写run方法?

     将自定义代码存储在run方法中,让线程运行;

   例:


class ThreadDemos1 extends Thread
{
public void run()
{
for(int x =0;x<10;x++)
{
System.out.println(this.getName()+" " + x);
}
}
}

//其中 this.getName 是获得线程的名称


class ThreadDemos2 extends Thread
{
ThreadDemos2(String name)
{
super(name);
}
public void run()
{
for(int x =0;x<10;x++)
{System.out.println(this.getName()+" " + x);
}
}
}

建立测试类



public class TestDemo {
public static void main(String[] args) {
ThreadDemos1 d1 = new ThreadDemos1();
d1.start();
ThreadDemos2 d = new ThreadDemos2("one");
d.start();
}
}







三  多线程运行状态


                                   阻塞状态

                                           |

线程建立——(start())——运行————sleep()————冻结

                                           |

                                        stop                                


四  自定义线程名称:




        ** 线程都有自己的名称 : Thread-标号  ,,  标号是从0开始的;

        **  获得线程名称的方法 : this.getName();     Thread.currentThread().getName()

        **  可以在线程初始化始时对线程命名;


       1.在线程初始化时候对其命名





class Demoss extends Thread
{
public void run()
{
for(int x =0;x<10;x++)
{
System.out.println(this.getName()+" " + x);
}
}
}

public class TestDemo {

public static void main(String[] args) {

Demoss d1 = new Demoss("one");
d1.start();


}
}


 2. 可以使用构造函数对其重命名;






class Demos extends Thread
{
Demos(String name)
{
super(name);
}
public void run()
{
for(int x =0;x<10;x++)
{
System.out.println(this.getName()+" " + x);
}
}
}

public class TestDemo {

public static void main(String[] args) {

Demos d1 = new Demos("one");
d1.start();


}
}



五 多线程的安全问题

1.同步 代码块

java对于多线程的安全问题,提供了专业的解决方式,就是  使用同步代码块,

结构         

synchronized(对象)

{

被同步的代码

}



例如一个售票例子

总共1000张票   四个售票机

package test;
public class TestDeoo {

public static void main(String[] args) {


Ticket t = new Ticket();


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();
}
}

class Ticket implements Runnable{
private int tick=1000;
Object obj = new Object();
public void run(){
while(true){
synchronized(obj){
if(tick>0){
" try{Thread.sleep(10);}catch(Exception e){ };
} <pre name="code" class="java">

System.out.println(Thread.currentThread().getName()+"sale"+tick--); } } }}





     2.同步代码块原理:

   例如有两个线程,当线程0获得CPU的执行权后,会读到synchronized代码块, 判断,然后会获得进入许可,继续执行下面的代码,随后synchronized 关闭入口,读到  stop时,线程结束,此时入口开放,等待下一线程的进入执行。。。。。。。。。。

3.使用同步代码块的前提

   <1> 必须有两个或者两个以上的线程

   <2> 必须是多个线程使用同一个锁

     4.同步代码块的好处

    解决了线程的安全问题

      5.同步代码块的弊端

   多个线程要判断锁,较为消耗资源

六 同步函数



public class StringDemo {

public static void main(String[] args) {
Cuss c = new Cuss();
Thread t = new Thread(c);
Thread t2 = new Thread(c);
t.start();
t2.start();
}
}

class Bank {
private int sum;
Object obj = new Object();

public void add(int x) {
synchronized (obj) {
sum = sum + x;
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println("sum " + sum);
}
}
}

class Cuss implements Runnable {
private Bank b = new Bank();

public void run() {
for (int x = 0; x < 3; x++) {
b.add(100);
System.out.println(Thread.currentThread().getName());
}
}
}







使用同步函数形式来写出上述问题

class Banks {
private int sum;
Object obj = new Object();

public synchronized void add(int x) {

sum = sum + x;
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println("sum " + sum);

}
}

class Cuss implements Runnable

{
private Banks b = new Banks();

public void run() {
for (int x = 0; x < 3; x++) {
b.add(100);
System.out.println(Thread.currentThread().getName());
}
}
}

public class stringDemo {

public static void main(String[] args) {
Cuss c = new Cuss();
Thread t = new Thread(c);
Thread t2 = new Thread(c);
t.start();
t2.start();
}
}


七  单例设计模式


 1.   饿汉式


class Single {
private static final Single s = new Singles();
private Single() {
}
public static Single getInstanceP
{
return s;
}
}





2. 懒汉式

class Single {

private static Single s = null;

private Single() {
}

public static Single getInstance() {

if (s == null) {

synchronized (Single.class) {

if (s == null) {
s = new Single();
}
}
}
return s;
}
}








线程间的通讯


 线程间的的通讯,其实就是多个线程在操作同一个资源;但是操作的动作不同的资源


新建一个资源:



class Res
{
String name;
String sex;

}






创建一个输入线程类:   输入与输出线程要操作同一个资源


class Input implements Runnable
{
Res r;
Input(Res r)
{
this.r=r;
}
public void run()
{
boolean b =true;
while(true)
{
if(b)
{
r.name="lishi";
r.sex="man";
b = false;
}
else
{
r.name="李四";
r.sex="男";
b = true;
}
}
}
}


新建一个输出线程:  输入线程与输出线程操作的是同一个资源




class Output implements Runnable
{
Res r;


Output(Res r)
{
this.r=r;
}

public void run()
{
while(true)
{
System.out.println(r.name);
}
}
}






新建一个测试类


public class TestDemo {

public static void main(String[] args)

{


Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);

Thread t = new Thread(in );
Thread tl = new Thread(out);
t.start();
tl.start();
}
}




这个程序的输出结果应该为  lishi  man

                                      李四   男

                                      。。。。。

测试一下,会出现乱码现象,如果要修改安全问题,就应该使用同步代码块



class Res
{
String name;
String sex;

}
class Input implements Runnable
{
Res r;
Input(Res r)
{
this.r=r;
}
public void run()
{
boolean b =true;
while(true)
{
synchronized(r)
{
if(b)

{
r.name="lishi";
r.sex="man";
b = false;
}
else
{
r.name="李四";
r.sex="男";
b = true;
}
}
}
}
}






class Output implements Runnable
{
Res r;


Output(Res r)
{
this.r=r;
}

public void run()
{

synchronized(r)
{
while(true)
{

System.out.println(r.name+" "+r.sex);
}
}
}
}




这样的话就解决了线程间的安全问题了


线程间的等待唤醒机制

新建一个资源


class Res
{
String name;
String sex;
boolean bo = false;

}


class Input implements Runnable
{
Res r;
Input(Res r)
{
this.r=r;
}
public void run()
{
boolean b =true;
while(true)
{
synchronized(r)
{
if(r.bo)
try{r.wait();}catch(Exception e){}
if(b)
{
r.name="lishi";
r.sex="man";
b = false;
}
else
{
r.name="李四";
r.sex="男";
b = true;
}
r.bo =true ;
r.notify();
}
}
}
}




class Output implements Runnable
{
Res r;


Output(Res r)
{
this.r=r;
}

public void run()
{
while(true)
{
synchronized(r)
{
if(!r.bo)
try{r.wait();}catch(Exception e){}
System.out.println(r.name+" "+r.sex);
r.bo=false;
r.notify();
}
}
}
}








public class StringDemo {


public static void main(String[] args)

{
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);

Thread t = new Thread(in );
Thread tl = new Thread(out);
t.start();
tl.start();

}
}






输出结果为

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男

lishi  man

李四  男



注  :  wait  :

           notify()

           notifyAll()


都使用在同步中,因为要对持有监视器的线程操作,所以要使用在同步中,因为只有 同步才具有锁;

为什么这些操作线程的方法要定义在object 类中呢?

因为这些方法在操作同步线程中,都必须要标识它们所操作线程的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中


优化后的代码


public class TestDemo {


public static void main(String[] args) {
Resi r = new Resi();
new Thread(new Inputi(r)).start();
new Thread(new Outputi(r)).start();
}
}
class Resi
{
String name;
String sex;
boolean bo = false;
public synchronized void set(String name ,String sex)
{
if(bo)
try{this.wait();}catch(Exception e){}
this.name = name;
this.sex = sex;
bo = true ;
this.notify();
}
public synchronized void out()
{
if(!bo)
try{this.wait();}catch(Exception e){}
System.out.println(name +" "+sex);
bo = false;
this.notify();
}
}


class Inputi implements Runnable
{
Resi r;
Inputi(Resi r)
{
this.r = r;
}

public void run()
{
boolean b =true;
while(true)
{
if(b)
{
r.set("lishi","man");
b = false;
}
else
{
r.set("李四","男");
b = true;
}
}
}
}

class Outputi implements Runnable
{
Resi r;
Outputi(Resi r)
{
this.r = r;
}
public void run()
{
while(true)
r.out();
}






生产者与消费者    线程间的通信



public class StringDemo {


public static void main(String[] args) {
Resourced r = new Resourced();
new Thread(new Producerd(r)).start();//1
new Thread(new Producerd(r)).start();//2
new Thread(new Consumerd(r)).start();//3
new Thread(new Consumerd(r)).start();//4
}
}




/*
* 生产一个,消费一个*/
class Resourced
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while(flag)
try{wait();}catch(Exception e){}
this.name = name+" "+count++;
System.out.println(Thread.currentThread().getName()+"生产者,,,," + this.name);
flag = true;
this.notifyAll();
}

public void out(){

while(!flag)
try{wait();}catch(Exception e){}

System.out.println(Thread.currentThread().getName()+"消费者 " + this.name);
flag = false;
this.notifyAll();
}
}








class Producerd implements Runnable
{
private Resourced res ;
Producerd(Resourced res)
{
this.res = res;
}
public void run()
{
while(true)
'7B
res.set("商品");
}
}
}







class Consumerd implements Runnable
{
private Resourced res;
Consumerd(Resourced res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}