Java基础之多线程
2017-06-16 12:53
155 查看
多线程
进程和线程的关系,举个形象的例子。360安全卫士就是一个进程,QQ是另外一个进程。在360中,我们可以同时进行电脑体检和电脑清理,这两个功能模块就是两个线程,他们并发执行。实现多线程的方法
继承Thread类
Thread类中有run()方法,这个方法就是封装自定义线程运行任务的函数,一般覆盖run()。步骤如下
定义一个类继承Thread
覆盖run方法
创建Thread子类对象创建线程
调用start方法
public class Print extends Thread { private int num; Print(int num) { this.num = num; } @Override public void run() { System.out.println("Thread" + num + " Run"); } } class ThreadDemo { public static void main(String[] args) { // 注意一个线程只能被start()一次 while (true) { new Print(1).start(); new Print(2).start(); } } }
CPU执行资格:可以被CPU处理,在处理队列中排队。
CPU执行权:正在被CPU处理。
线程冻结时:放弃了执行权也放弃了执行资格。
临时阻塞:加入甲乙丙都有执行资格,而只有甲有执行权,此时乙丙就出于临时阻塞状态,有执行资格,无执行权。
实现Runnable
若是几个线程共用一个数据,继承自Thread就不行了,因为每个子类都有自己的数据。这时候需要实现Runnable。比较以下例子。public class Bank extrends Thread { private int money = 100; @Override public void run() { money--; System.out.println(money); } public static void main(String[] args) { new Bank().start(); new Bank().start(); new Bank().start(); new Bank().start(); // 这里打印四个99,说明每个线程用的都是自己的的money } } public class Bank implements Runnable { private int money = 100; @Override public void run() { money--; System.out.println(money); } public static void main(String[] args) { Bank a = new Bank(); new Thread(a).start(); new Thread(a).start(); new Thread(a).start(); new Thread(a).start(); // 传入某个特定的Bank,这里打印99,98,97,96,实现Runnable多了线程可以共用一个数据 } }
实现Runnable接口
覆盖run方法
通过Thread类创建子对象,并将Runnable接口子类作为Thread类的构造函数参数进行传递
Demo d = new Demo();
Thread t1 = new Thread(d);
调用start方法
实现Runnable接口的好处
几个线程可以共用同一份数据避免了Java单继承的局限,比如
class Demo extends Fu implements Runnable;一般开发中用这种方式较多。
线程安全
产生原因
多个线程在共用同一个数据时操作共享数据的线程代码有多余,当一个线程在执行操作共享数据的多余代码的过程中,其他线程又参与运算,就会导致线程安全。
解决办法
解决上述问题的方法,可以封装这些多余代码,当一个线程执行时,其他线程不能进入。synchronized代码块
// 这里需要传入一个对象,即同步锁,可以看成一个标志位,有一个线程进来了,就从1 -> 0,其他线程进不去,等进入的线程执行完毕后,标志位再从0 -> 1 syschronized(Object) { // 需要封装的多余代码 }
同步
同步的好处:课解决线程安全问题同步的缺点:效率低,因为同步外的线程都会判断同步锁
同步的前提:多个线程用了共享的数据且共用一把同步锁,作为锁的这个对象必须在run()方法之外。
同步函数
// 同步锁去哪儿了?这里默认用的是this public synchronized void func() { }
同步代码块可以使用任意对象作为锁,而同步函数只能用this。
若同步函数是static的,用的锁是该函数所属的字节码文件对象,可以用
类名.class获取,不能用
this.getClass()因为静态函数加载的时候还没有对象
死锁
嵌套锁或造成死锁,即一个线程拿走了另外一个线程的锁。所有线程都在线程池也会死锁。
进程间通信:wait()将线程冻结,存储到线程池中等待。notify()会唤醒线程池中任一个线程,若本方唤醒了自己,没有意义,while+notify会导致死锁。while+notifyAll可解决。
wait()和sleep()
sleep()需要指定时间,毫秒级。< -- > wait()课指定时间也可不指定。sleep()释放执行权,不释放锁。< -- > wait()释放执行权也释放锁。
多线程新特性
以下代码和synchronized代码块作用类似。注意try里是瞎写的,只是为了演示新特性的新方法。Lock lock = new ReentrantLock(); // Condition可以和任意的锁组合使用 Condition condition = lock.newCondition(); // 在这里上锁 lock.lock(); try { // 这三个函数相当于wait()、notify()、notifyAll() condition.await(); condition.signal(); condition.signalAll(); // 最后要释放锁 } finally { lock.unlock(); }
继承自Object的几个方法
equals() {return this==other}默认是比较地址。可以覆盖,比如String类、Integer类覆盖后比较的是内容或值。
hashcode两个对象的哈希值相同,才能说他们具有相同的地址。
getClass(),返回此Object的运行时类,字节码文件对象。
java Person p1 = new Person(); Person p2 = new Person(); // Class xx = p1.getClass(); p1.getClass() == P2.getClass() // true,两个对象指向的类Person
toString()将对象转换为字符串,如直接打印上面的
p1,其实默认调用了
p1.toString(),其内部实现实际是返回了多个由
+连接的字符串。
Integer的一些方法
int a = Integer.parseInt("6"); // 其他进制转为十进制,第二个参数为进制 int b = Integer.parseInt("110", 2); // 十进制转为其他进制 String c = Integer.toBinaryString(6); String d = Integer.toHexString(10); // 和parseInt和相似的方法,parse返回int,valueOf返回Integer对象 // 其他进制转十进制 Integer aa = Integer.valueOf("110", 2);
by @sunhaiyu
2016.12.14
相关文章推荐
- Java多线程编程基础之线程对象
- java多线程基础
- java基础巩固训练营【第一轮】(十) 多线程 补充
- java多线程开发基础
- JAVA多线程编程基础1
- Java多线程基础知识
- 学习笔记7—Java基础5_多线程
- [零基础学JAVA]Java SE应用部分-25.多线程(03) 推荐
- [零基础学JAVA]Java SE应用部分-24.多线程(02) 推荐
- java基础——多线程
- java多线程基础
- 如何使用Java编写多线程程序-Java基础-Java-编程开发
- Java多线程编程基础
- [零基础学JAVA]Java SE应用部分-26.多线程(04) 推荐
- Java多线程程序设计入门-Java基础-Java-编程开发
- java多线程 基础(二) Thread Runnable
- java多线程基础
- 浅析Java多线程程序设计机制-Java基础-Java-编程开发
- Java基础很重要(四)---多线程
- Java多线程基础