黑马程序员之---多线程

 ------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

Thread: 线程:

 

进程:正在运行的应用程序

线程:进程中的一条执行路径

 

单线程: 应用程序只有一条执行路径

多线程: 应用程序有多条执行路径

 

创建线程对象的三种方式:

方式1: 继承Thread

a: 自定义类 继承 Thread

b: 重新Thread类中的run()方法

c: 创建自定义类对象(线程对象)

d: 启动线程? start()方法

例题:

//a:创建自定义类 继承 Thread

public class MyThread extends Thread {

 

//b:重写Thread类中run方法

@Override

public void run() {

System.out.println("我的线程 启动了");

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

System.out.println(i);

}

}

}

public class ThreadDemo {

public static void main(String[] args) {

//c:通过子类,完成线程对象的创建

MyThread my = new MyThread();

MyThread my2 = new MyThread();

//d:调用start()完成线程对象的启动

my.start();

my2.start();

 

}

}

 

方式2: 实现Runnable

a: 自定义类  实现 Runnable

b: 实现接口中的run()方法

c: 创建自定义类对象

d: 创建Thread对象,然后把自定义类对象 作为构造方法的参数使用

e: 开启线程, start()方法

例题:

//a: 自定义类 实现Runnable接口

public class MyRunnable implements Runnable {

//b: 实现接口中的run()方法

@Override

public void run() {

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

//System.out.println(getName() +"---"+ i);

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

}

}

}

public class ThreadDemo {

public static void main(String[] args) {

//c: 创建自定义类对象

MyRunnable my = new MyRunnable();

//创建线程对象

//Thread t1 = new Thread(my);

Thread t1 = new Thread(my, "班长");

Thread t2 = new Thread(my, "赵日天");

//启动线程

t1.start();

t2.start();

}

}

方式3通过线程池, 实现Callable接口,实现call()方法

面试题:

Thread类中方法:

public final String getName()      返回该线程的名称

public final void setName(String name) 改变线程的名称使之与参数name的名称相同

public static Thread currentThread() 返回当前正在执行的线程的对象的引用

 

线程优先级

public final int getPriority()  返回线程的优先级

public final void setPriority(int newPriority)     更改线程的优先级

线程休眠

public static void sleep(long millis)

线程加入

public final void join()

线程礼让

public static void yield()

后台线程

public final void setDaemon(Daemon(boolean on) 将该线程标记为守护线程,当正在运行的线程都为守护线程的时候JVM虚拟机退出

中断线程

public final void stop() 结束当前正在运行的线程

public void interrupt() 中段当前正在运行的线程,抛出一个中断异常,而程序还可以继续运行

中断线程:

public class InterruptThread extends Thread {

 

public InterruptThread() {

super();

}

public InterruptThread(String name) {

super(name);

}

@Override

public void run() {

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

System.out.println(getName() + "---" + i);

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class InterruptDemo {

public static void main(String[] args) {

//创建线程对象

InterruptThread t1 = new InterruptThread("班长");

//启动线程

t1.start();

//将当前正在运行的线程10秒后,中断

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

//t1.stop();//停止

try {

t1.interrupt();

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("over");

}

}

同步机制:

解决多线程安全问题 

同步代码块

格式:

synchronized (锁对象) {

需要同步的代码

}

锁对象可以为任意对象

同步方法

(普通同步方法)  锁对象为this

(静态同步方法) 锁对象为类名.class

格式:

修饰符 synchronized 返回值类型 方法名(参数列表){....}

注意:

同步代码块,如果有多个同步代码块,那么锁对象,要求一致

同步方法,同步方法的锁对象是谁?  this

同步方法,同步静态方法的锁对象是谁?  字节码文件对象, 类名.class

案例:电影院卖票问题

    public class Ticket implements Runnable {

static int ticket = 100;

 

//定义一个锁对象这个对象可以是任意的

Object objA = new Object();

Object objB = new Object();

// this

// 类名.class 产生一个字节码文件对象  ---getClass()

int x = 0;

@Override

public void run() {

while (true) {

if (x %2 == 0) {

//同步方法 

//method();

//静态同步方法

method2();

} else {

//同步代码块

//synchronized (objA){

//synchronized (objB){

//synchronized (this){

//synchronized (super){

synchronized (Ticket.class){

//synchronized (new Object()){//错误的

if (ticket>0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+"正在卖票" + ticket--);

}

}

}

x++;

}

}

 

//静态同步方法

public static synchronized void method2() {

//synchronized (objA){//正确的

if (ticket>0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+"正在卖票" + ticket--);

}

//}

}

//同步方法

public synchronized void method() {

//synchronized (objA){//正确的

if (ticket>0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+"正在卖票" + ticket--);

}

//}

}

}

public class TicketThread {

public static void main(String[] args) {

//模拟3个窗口, 卖票

//创建自定义类对象

Ticket ticket = new Ticket();

//创建线程对象,把自定义类对象 作为构造方法的参数

Thread t1 = new Thread(ticket, "窗口1");

Thread t2 = new Thread(ticket, "窗口2");

Thread t3 = new Thread(ticket, "窗口3");

//启动线程

t1.start();

t2.start();

t3.start();

}

Collections

public static 集合 synchronizedXxx(Xxx 集合): 把不同步的集合, 变成 线程同步的集合 

 集合案例:

public class ThreadDemo {

public static void main(String[] args) {

//线程安全的集合

Vector v = new Vector();

Hashtable table = new Hashtable();

//线程安全的类

StringBuffer sb = new StringBuffer();

//创建一个线程不安全的集合

ArrayList list = new ArrayList();

//将线程不安全的集合, 变为 线程安全的集合

List synchronizedList = Collections.synchronizedList(list);

}

}

 

Lock锁: jdk1.5以后提供

void lock()获取锁。 

void unlock()释放锁。

 

死锁:

是指两个或者两个以上的线程在执行的过程中,因争夺资源(锁对象)产生的一种互相等待现象

public class DieThread extends Thread {

public boolean flag;

public static Object objA = new Object();

public static Object objB = new Object();

 

//构造方法

public DieThread(String name, boolean b) {

super(name);// 调用Thread类中的构造方法,完成设置线程名称

flag = b;

}

 

@Override

public void run() {

while (true) {

if (flag) {

//对象1

synchronized (objA) {

System.out.println(getName() + "if-- ObjA");

synchronized (objB) {

System.out.println(getName() + "if-- ObjB");

}

}

} else {

//对象2

synchronized (objB) {

System.out.println(getName() + "else-- ObjB");

synchronized (objA) {

System.out.println(getName() + "else-- ObjA");

}

}

}

}

}

}

//测试类

public class ThreadTest {

public static void main(String[] args) {

//创建线程对象

DieThread t1 = new DieThread("对象1", true);

DieThread t2 = new DieThread("对象2", true);

t1.start();

t2.start();

}

}

 

等待唤醒机制:

等待:

wait(): 让当前的线程等待,释放锁对象,让其他线程获取锁对象与CPU执行权,

等待着其他线程 调用 notify()\notifyAll()来 唤醒

唤醒:

notify()\notifyAll() : 可以唤醒当前锁对象上面的等待的线程

notify(): 随机唤醒锁对象上面的其中一个等待的线程对象

notifyAll(): 唤醒锁对象上面的所有等待的线程对象

线程组:  它是线程的集合(包含对象线程对象)

生产商生产手机,消费者购买手机案例:

//手机生产商生产手机

public class SetPhone implements Runnable {

Phone phone ; 

int num = 0;

public SetPhone(Phone p) {

phone = p;

}

@Override

public void run() {

while (true) {

if (num %2 == 0) {

phone.set("小米4","蓝色");

} else {

phone.set("苹果6s", "黄色");

}

num++;

}

}

}

//消费者购买手机

public class GetPhone implements Runnable {

Phone phone;

public GetPhone(Phone p) {

phone = p;

}

@Override

public void run() {

while (true) {

phone.get();

}

}

}

//手机类

public class Phone {

public String brand;

public String color;

public boolean isNewPhone = false;// 代表当前有新手机

//true 代表有新手机

//false 没有新手机

//生产手机

public synchronized void set(String brand, String color) {

//是否有新手机

if (this.isNewPhone) {

//说明有新手机

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

//如果到了当前代码位置,说明没有新手机,要生产新手机

//生产手机

this.brand = brand;

this.color = color;

//模拟生产手机的耗时操作

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.print(Thread.currentThread().getName());

System.out.println("生产了," +this.brand + "---" + this.color);

//手机生产完成,把手机状态 更新为 有新手机 true

this.isNewPhone = true;

//唤醒消费者,告诉她,有新手机了,可以购买

this.notify();

}

 

//购买手机

public synchronized void get() {

//判断是否有新手机

if (!this.isNewPhone) {

//说明没有新手机, 等待

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

//执行到了当前代码,说明目前有手机了

//购买手机

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.print(Thread.currentThread().getName());

System.out.println("购买了," + this.brand +"---" +this.color);

//手机被买走了,更新手机的状态,  false

this.isNewPhone = false;

//唤醒生产商,通知生产商 生产新手机

this.notify();

}

}

//测试类

public class PhoneTest {

public static void main(String[] args) {

//手机对象

Phone p = new Phone();

//生产商

SetPhone set = new SetPhone(p);

//消费者

GetPhone get = new GetPhone(p);

//创建线程对象

Thread setThread = new Thread(set, "生产商");

Thread getThread = new Thread(get, "消费者");

//启动线程

setThread.start();

getThread.start();

}

}

 

 

线程组的使用:

1: 获取线程所在的组:

getThreadGroup();

2:  设置线程 所在的组:

通过Thread类的构造方法来完成

public class MyThread extends Thread {

public MyThread() {

super();

}

public MyThread(ThreadGroup group, String name) {

super(group, name);

}

@Override

public void run() {

System.out.println("当前线程的名字是:" + getName());

//获取到线程组对象

ThreadGroup threadGroup = this.getThreadGroup();

//获取线程组的名字

String name = threadGroup.getName();

System.out.println("当前线程对象所在的组名是: " + name);

}

}

public class MyThreadGroup extends ThreadGroup {

public MyThreadGroup(String name) {

super(name);

}

}

public class ThreadDemo {

public static void main(String[] args) {

//创建一个线程组

MyThreadGroup group = new MyThreadGroup("javase0322");

//创建一个新的线程对象,并把该线程对象 设置为javase0322组的成员

MyThread t3 = new MyThread(group, "对象");

t3.start();

group.setMaxPriority(10);//组内所有的线程 优先级统一成为10

group.setDaemon(true);

}

}

 

线程池:(线程的容器,可以有多个线程对象)

线程池的使用:

1: 创建线程池对象

a: 创建一个具备缓冲功能的线程池

public static ExecutorService newCachedThreadPool()

b: 创建一个可重用固定线程数的线程池

public static ExecutorService newFixedThreadPool(int nThreads)

c: 创建具备一个线程对象的线程池

public static ExecutorService newSingleThreadExecutor()

2: 创建Runnable [ run() ] 接口的类对象, 或者创建一个Callable[ call() ]接口类的对象

3: 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future

Future<?> submit(Runnable task)

   提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future

<T> Future<T> submit(Callable<T> task)

理解为: 获取线程池中的线程对象, 让获取到的线程对象,执行Runnable中的run()方法 

 获取线程池中的线程对象, 让获取到的线程对象,执行Callable中的call()方法

4: 关闭线程池

void shutdown()

匿名内部类的方式实现多线程程序:

格式1

new Thread(){

run(){.....};

}.start();

格式2

new Thread(

    new Runnable(){

run(){.....}

}

).start();

例题:

public class ThreadDemo {

public static void main(String[] args) {

//匿名内部类,Thread类的子类

new Thread(){

//Thread类的匿名子类对象

public void run() {

System.out.println("今天凉快");

};

}.start();

//--------------------------------

//匿名内部类方式,实现Runnable接口

new Thread(new Runnable() {

@Override

public void run() {

System.out.println("今天天气真好");

}

}).start();

//---------------------------------

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

new Thread(new Runnable() {

@Override

public void run() {

System.out.println("阳光明媚");

}

}).start();

}

//--------------------------------

//变态用法

new Thread(new Runnable() {

//实现Runnable接口的方式

@Override

public void run() {

System.out.println("abc");

}

}){

//子类对象方式

public void run() {

System.out.println("123");

};

}.start();

}

}

定时器:

Timer: 定时器类

作用: 创建一个定时器对象, 在指定的时间 执行指定任务

public void schedule(TimerTask task,  Date time)

public void schedule(TimerTask task,  long delay)

public void schedule(TimerTask task,  long delay, long period)

TimerTask: 定时器任务类 

作用: 通过Timer对象, 来调用当前对象中的方法run()

 

案例:

public class TimerDemo {

public static void main(String[] args) {

//3秒钟后 闹钟响起

Timer timer = new Timer();

//准备好定时器Timer一会要执行的内容(任务)

TimerTask task = new TimerTask() {

@Override

public void run() {//此计时器任务要执行的操作

System.out.println("节日快乐");

}

};

timer.schedule(task, 3000);//3秒后执行task任务

//-----------------------------------------

//5秒钟后 闹钟响起以后每隔3秒响一次

Timer timer2 = new Timer();

//准备好定时器Timer一会要执行的内容(任务)

TimerTask task2 = new TimerTask() {

@Override

public void run() {

System.out.println("节日快乐");

}

};

timer.schedule(task, 5000, 3000);

}

}

 

设计模式: 其实,就是开发经验的总结, 把总结进行了精华的提取,得出了一套(编写)设计代码的(方式)模式,  这种方式叫 设计模式

单例模式:

饿汉式:

上来就创建对象并使用

线程安全的

class Teacher{

//构造方法私有

private Teacher(){};

//在本类创建,本类对象

private static Teacher t = new Teacher();

//提供一个公共访问方法

public static Teacher getInstance(){

return t;

}

}

懒汉式:

需要用到对象的时候,再调用方法, 创建对象

线程不安全的, 需要加同步处理

class Teacher{

//构造方法私有

private Teacher(){};

//在本类创建,本类对象引用,不创建对象

private static Teacher t = null;

//提供一个公共访问方法

public static synchronized Teacher getInstance(){

if (t == null) {

t = new Teacher();

}

return t;

}

}

Runtime:

它是一个单例设计模式的类

exec()方法: 可以执行其他的应用程序

 

        

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值