Java多线程之冰山一角

一.   多线程原理

线程类:

//继承线程类,重写run方法

public class MyThread extends Thread{

    public void run(){

        for (int i = 0; i < 100; i++) {

            System.out.println("i="+i);

        }

    }

}

测试类:

//启动线程

public class Demo01 {

     //主线程

    public static void main(String [] args){

        //创建子类对象

        MyThread myThread=new MyThread();

        //调用父类的start方法,启动多线程

        myThread.start();

        for (int k = 0; k < 100; k++) {

            System.out.println("k="+k);

        }

    }

}

多个线程运行原理:

1.当主线程启动一个独立了的线程后,这个独立的线程就会与主线程“同时”运行;

2.对于单颗,单核CUP来说,在某一个时间点上,CPU中只有一个线程在运行(由操作系统分配时间片,时间片用完后切换其他的线程)一段时间。

二.  1.     创建线程的方式一:继承Thread类及其常用方法

步骤:

(1)  自定义线程类,继承Thread

(2)  重写Thradrun()方法(线程中要完成的功能就放在run()方法中);

3)启动线程

a.创建线程类对象

b.调用对象的start()方法

示例代码:同上

2.  使用线程时的注意事项:

(1)  一个线程类可以创建多个线程对象,每个线程对象都可以单独启动;

(2)  一个线程对象只能启动一次(即调用一次start()方法);

(3)  在线程类中,重写的时run() 方法,但是在测试了中启动线程调用的是start() 方法。

3.  Thread类中的常用方法

1public String getName()   获取线程名称

       注:每个线程都有一个默认的线程名称:Thread—索引值

2public  void  setName ()          设置线程名称

3public  static  currentThread ()    获取当前线程对象

4public  static  sleep()              使线程休眠指定的毫秒数

示例代码:

线程类:

public class MyThread extends Thread{

    public void run(){

        for (int i = 0; i < 100; i++) {

            System.out.println(this.getName()+"  i="+i);

            try {

                Thread.sleep(1000);//休眠指定的毫秒数

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

}

       测试类:

public class Demo01 {

    public static void main(String [] args){

        //创建子类对象

        MyThread myThread=new MyThread();

        myThread.setName("独立线程");//设置线程名称

        Thread.currentThread().setName("主线程");//设置线程名称

        //调用父类的start方法,启动多线程

        myThread.start();

        for (int k = 0; k < 100; k++) {

            System.out.println(Thread.currentThread().getName()+"  k="+k);//获取当前线程对象

            try {

                Thread.sleep(1000);//休眠指定的毫秒数

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

}

三.  创建线程的方式二:实现Runnable接口

1.  步骤

(1)  自定义类实现Runnable接口;

(2)  重写run() 方法;

(3)  启动线程

a.  创建一个自定义对象

b.  创建一个Thread对象,并将自定义对象作为参数传给Runnable的构造方法;

c.  调用方Thread对象的start()方法启动线程。

 

 

线程类:

public class MyRunnable implements Runnable {

    @Override

    //重写Runnable中的run() 方法

    public void run() {

        for (int i = 0; i < 100; i++) {

            System.out.println(Thread.currentThread().getName()+"   i="+i);

            //休眠指定的毫秒数

            try {

                Thread.sleep(1);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

}

 

测试类:

public class Demo {

    public static void main(String[] args) {

        //创建自定义类对象

        MyRunnable myRunnable=new MyRunnable();

        //创建Thread对象,并将自定义对象作为参数传给Thread的构造方法

        Thread thread=new Thread(myRunnable);//调用Thread对象的start()方法启动线程

        //为线程设置名称

        thread.setName("独立线程");

        Thread.currentThread().setName("主线程");

        thread.start();

        for (int k = 0; k < 100; k++) {

            System.out.println(Thread.currentThread().getName()+"   k="+k);

            //休眠指定的毫秒数

            try {

                Thread.sleep(1);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

}

 

四.  两种创建线程的区别

1.  Thread 通过继承方式实现多线程,这就限制了子类的继承关系;

2.  Runnable 通过实现接口的方式实现多线程,不会对实现类造成限制,较为灵活。

五.  匿名内部类的方式实现线程

1.  使用Thread匿名子类

public class ThreadDemo {

    public static void main(String[] args) {

        new Thread(){

            public void run(){

                for (int i = 0; i < 100; i++) {

                    System.out.println("i="+i);

                }

            }

        }.start();

        for (int k = 0; k < 100; k++) {

            System.out.println("k="+k);

        }

    }

}

2.  使用Runnable

public class RunnableDemo {

    public static void main(String[] args) {

        new Thread(new Runnable() {

            @Override

            public void run() {

                for (int i = 0; i < 100; i++) {

                    System.out.println("i=" + i);

                }

            }

        }).start();

        for (int k = 0; k < 100; k++) {

            System.out.println("k="+k);

        }

    }

}

六.  多线程的安全问题

1.  不安全的火车票售票机制

线程类:

public class Tickets implements Runnable  {

    private int tickets=100;

    @Override

    public void run() {

       while(true){

           try {

               Thread.sleep(1);

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

           if(tickets>0){

               System.out.println("给线程"+Thread.currentThread().getName()+"取走一张票"+tickets);

               tickets--;

           }else{

               System.out.println("没票了...");

               break;

           }

       }

    }

}

 

测试类:

public class Demo {

    public static void main(String[] args) {

        //创建线程类对象

        Tickets tickets=new Tickets();//休眠一毫秒,可以更加明显

        //创建Thread对象,将Runnable对象作为参数传给Thread的构造方法,通过Thread对象调用方法

        Thread t1=new Thread(tickets);

        Thread t2=new Thread(tickets);

        Thread t3=new Thread(tickets);

        //设置线程名称

        t1.setName("窗口1");

        t2.setName("窗口2");

        t3.setName("窗口3");

        //启动线程

        t1.start();

        t2.start();

        t3.start();

    }

}

此时会出现一张票被多个人买走的情况,非常的不安全。

七.  线程同步解决线程安全问题

1.  使用同步代码块解决多线程安全问题

public class Tickets implements Runnable  {

    private int tickets=100;

    Object obj=new Object();

    @Override

    public void run() {

       while(true) {

           try {

               Thread.sleep(1);

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

           synchronized (obj) {

               if (tickets > 0) {

                   System.out.println("给线程" + Thread.currentThread().getName() + "取走一张票" + tickets);

                   tickets--;

               } else {

                   System.out.println("没票了...");

                   break;

               }

           }

       }

    }

}

//测试类同上

 

2.  使用同步方法解决多线程安全问题

public class Tickets implements Runnable {

    //Object obj=new Object();

    int tickets=100;

    @Override

    public void run() {

        while(true){

            getTickets();

            try {

                Thread.sleep(2);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

    public synchronized  void getTickets() {

       if(tickets>0){

           System.out.println("线程"+Thread.currentThread().getName()+"取走了一张票"+tickets);

           tickets--;

       }else {

           System.out.println("没票了....");

           System.exit(0);

       }

    }

}

 

 

说明:同步方法可以是普通方法,也可以是静态方法。只要这个方法被多个线程同时访问,但是程序值希望只有一个线程执行全部方法体后,才允许其他线程访问,这种情况下可以将方法声明为同步方法,这样可以保证数据的安全性。

https://www.cnblogs.com/LLLaoJia/

posted @ 2018-08-19 22:02  叹叹  阅读(200)  评论(0编辑  收藏  举报