1.创建线程
- 创建一个线程的方法:
- 方法一:继承Thread类
-
1).创建一个类继承于Thread 类
-
2).重写run 方法
-
3).通过对象的start的方法启动线程,但不能通过run方法来启动线程
- 创建线程方法二 :Runable
-
1)创建一个类实现Runable接口
-
2)实现抽象run方法
-
3)创建实现类对象,
-
4)将此对象作为参数传递给Thread类的构造器创建Thread类的对象
-
5)通过Thread类对象的start方法启动线程
- 两种方式的比较
- Runnable优先选择。原因:1.单继承的弊端;2.实现Runnable类方式通过将共享数据放在实现类,更适合共享数据的处理。
例子:
在这里插入代码片`public class CreatThread {
public static void main(String[] args) {
MyThread thrad = new MyThread();
testafter();
thrad.start();
//匿名创建子类的方法
new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
}
}.start();
//通过Runnable来创建线程
Thread th = new Thread(new RunThread());
th.start();
MethodMain();
}
public static void testafter() {
for (int i = 0; i < 500; i++) {
System.out.println("running in main ");
}
}
private static void MethodMain()
{
for (int i = 0; i < 20 ; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 400; i++) {
System.out.println("Runing in Thread run");
System.out.println(Thread.currentThread().getName());
}
}
}
class RunThread implements Runnable{
@Override
public void run() {
System.out.println("implement RunThread run method!");
}
}
`
2.常用方法
/**
-
start()方法,线程从 新建 状态变成 就绪 状态,等待获得cpu的执行权
-
static Thread.currentThread() //返回当前代码执行的线程(返回对象)
-
getName()获得当前线程的name
-
setName()设置当前线程的name
-
yield()释放当前cpu的执行权
-
join()在线程 A 中调用线程 B 的 join 方法,此时,线程 A 进入阻塞状态,直到线程B执行完才继续执行A线程
-
static void sleep(long millionseconds)阻塞millionseconds毫秒,try-catch
-
isAlive()判断当前线程是否还在执行
-
线程优先级(cpu执行的概率,而不是先后执行,高优先级的线程抢占低优先级的线程的执行 权)
-
MAX_PRIORITY = 10
-
NORMAL_PRIORITY = 5 默认
-
MIN_PRIORITY = 1
-
获取设置优先级
-
>setPriority()
-
>getPriority()
3.线程安全问题
以买票程序为例
出现的重票和错票就是线程现象,是一种线程安全问题
当某个线程正在操作共享数据时,但操作还没完成时。另一个线程也来操作共享数据,引起线程不安全
-
解决措施:
当一个线程在操作一个共享数据的时候,其他线程不能擦于进来—线程锁
在Java中用同步机制来解决线程安全问题 -
方式一:同步代码块
-
synchronize(同步监视器){
-
//需要被同步的代码,即操作共享数据的代码
-
}
-
思路:
-
同步监视器即 “锁”,任何一个类的对象都可以来充当锁
-
要求: 多个线程用一个锁
-
评价: 解决了线程安全问题, 但是实质上却是一个单线程, 降低了效率。但还是都是用这个方法
-
1.解决实现Runnable类方式的线程安全问题。
-
2.结决继承Thread类线程安全问题
-
方式二:
-
使用同步方法
-
1.使用方法解决Runnable实现类方式的线程安全问题
-
2.同步方法解决继承Thread类方式线程安全问题
**/
public class ThreadSafe {
public static void main(String[] args) {
//实现类方式同步测试
Windows runnable = new Windows();
Thread w1 = new Thread(runnable);
Thread w2 = new Thread(runnable);
Thread w3 = new Thread(runnable);
w1.setName("窗口1 ");
w2.setName("窗口2 ");
w3.setName("窗口3 ");
w1.start();
w2.start();
w3.start();
//继承方式同步测试
HWindow win1 = new HWindow();
HWindow win2 = new HWindow();
HWindow win3 = new HWindow();
win1.setName("窗口1");
win2.setName("窗口2");
win3.setName("窗口3");
win1.start();
win2.start();
win3.start();
//测试同步方法解决Runnable继承类
IWindow iwin = new IWindow();
Thread th1 = new Thread(iwin);
Thread th2 = new Thread(iwin);
Thread th3 = new Thread(iwin);
th1.setName("窗口1 ");
th2.setName("窗口2 ");
th3.setName("窗口3 ");
th1.start();
th2.start();
th3.start();
//同步方法--继承方式测试
HWindow2 win1 = new HWindow2();
HWindow2 win2 = new HWindow2();
HWindow2 win3 = new HWindow2();
win1.setName("窗口1");
win2.setName("窗口2");
win3.setName("窗口3");
win1.start();
win2.start();
win3.start();
}
}
class Windows implements Runnable {
private int tickets = 100;//不同加static,传递的同一个Windows2
// private final Object obj = new Object();
@Override
public void run() {
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// while (tickets > 0) {
// System.out.println(Thread.currentThread().getName() + "出售票号为:" + tickets);
// tickets--;
// }
//利用线程锁
while (true) {
//synchronized (obj)
synchronized (this){
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "出票" + tickets);
tickets--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else
break;
}
}
}
}
/**
* 继承方式同步问题解决
**/
class HWindow extends Thread {
private static int tickets = 100;
private static final Object obj = new Object();
@Override
public void run() {
while (true) {
//synchronized (obj)
synchronized (HWindow.class){
if (tickets > 0) {
System.out.println(getName() + " 出售票号为 :" + tickets);
tickets--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else break;
}
}
}
}
//使用同步方法解决同步问题
class IWindow implements Runnable{
private int tickets = 100;
@Override
public void run() {
while(true){
sellTickets();
if (tickets <= 0)
break;
}
}
// 同步方法,同步监视器为this
private synchronized void sellTickets(){
if(tickets > 0){
System.out.println(Thread.currentThread().getName() + "出售票号 "+ tickets);
tickets--;
}
}
}
//使用同步方法解决继承方式线程安全问题
class HWindow2 extends Thread{
private static int tickets = 100;
@Override
public void run() {
while(true){
sellTickets();
if(tickets <= 0)
break;
}
}
//必须为静态方法,监视器为: Hwindow.class
private static synchronized void sellTickets(){
if(tickets > 0){
System.out.println(Thread.currentThread().getName() + "出售票号 "+ tickets);
tickets--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4懒汉式单例模式线程安全方式
lass Bank{
private static Bank bank= null;
private Bank(){}
public static Bank GetInstance(){
/*
* 效率较高的一种方式,后面的线程到这个if语句的时候bank已经不是null, 就不再进入等待*/
if(bank == null) {
synchronized (Bank.class) {
if (bank == null) {
bank = new Bank();
}
}
}
return bank;
}
}