在这之前首先重复一下获取通道的4种方式:
通道:获取通道的方式1
FileInputStream in = new FileInputStream(“a.txt”);
FileOutputStream out = new FileOutputStream(“aa.txt”);
FileChannel 本地的文件传输通道
FileChannel inChannel = in.getChannel();
FileChannel outChannel = out.getChannel();
获取通道方式2
FileChannel inChannel = FileChannel.open(Paths.get(“a.txt”), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get(“bb.txt”), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
获取通道的方式三 JDK1.7 提供了一个类 Files
SeekableByteChannel inChannel = Files.newByteChannel(Paths.get(“a.txt”), StandardOpenOption.READ);
SeekableByteChannel outChannel = Files.newByteChannel(Paths.get(“cc.txt”), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
获取通道的方式4 JDk1.7 有个 Channels
ReadableByteChannel inChannel = Channels.newChannel(new FileInputStream(“a.txt”));
WritableByteChannel outChannel = Channels.newChannel(new FileOutputStream(“dd.txt”));
除此之外,我们还可以直接通过通道传输,代码如下:
直接从输入通道传个输出通道
inChannel.transferTo(0,inChannel.size(),outChannel);
站在输出通道的角度来看
outChannel.transferFrom(inChannel,0,inChannel.size());
接下来我们就开始讲解线程:
线程
Java中的多线程,执行是随机的。因为Java中的线程调度模式是抢占式调度,线程优先级高的优先使用,但这也仅限于可能性。
方式一:extends Thread
让该类继承Thread,重写run方法。然后再在主函数里通过创立该类的对象,再通过对象调方法。
可使用的方法
- Thread.sleep();让线程休眠
MyThread th1 = new MyThread() - join(): 方法可以将多个线程并发的执行,转换成串行。意思就是等待该线程执行完毕了以后, 其他线程才能再次执行
注意事项:
在线程启动之后, 在调用方法,如下
th1.start();
th1.join();
3.守护线程
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。通俗点来说,就是不管此线程的死活了。
th1.setDaemon(true);
th1.start();
开启方法如上,开启守护线程必须在线程开启前调用。
4,打断线程的阻塞
Thread.sleep(1000);
th1.interrupt();打断线程的阻塞状态,让线程继续运行
如上,让线程休眠就是让其阻塞的一种现象,此时如果要让线程立马启动,interrupt方法合适。
方式二:implements Runnable(声明实现runnable接口)
让该类实现runnable接口之后实现run方法,再然后让其在创建Thread类时作为参数传递实现,但该方法无法抛出异常,只能抓取,因为接口没抛,子类也不能抛
MyRunable myRunable = new MyRunable();
Thread th = new Thread(myRunable,"线程名称");
th.start();
方式三:实现 Callable 接口
相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
实现步骤
- 创建一个类实现Callable 接口
- 创建一个FutureTask类将Callable接口的子类对象作为参数传进去(执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。FutureTask 是 Future 接口的实现类)
- 创建Thread类, 将FutureTask对象作为参数传进去
- 开启线程
MyCallable myCallable = new MyCallable();
FutureTask<Integer> integerFutureTask = new FutureTask<>(myCallable);
Thread th = new Thread(integerFutureTask);
th.start();
//获取线程执行完之后,返回的结果
Integer integer = integerFutureTask.get();
System.out.println(integer);
Callable 返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
多线程的安全问题
出现线程安全的问题:得符号三个条件
1.是否是多线程环境
2.是否有共享数据
3.是否有多条语句在操作这个共享数据
出现问题3的原因大多是因为原子性所导致(原子性:不可再分割),因为数据操作很快,所以有可能出现多个线程同时操作一个数据的现象。
解决文体的方法,可以通过锁对象的方法
锁对象的方法
1,老式方法
synchronized (锁对象){
//需要被同步的代码
}
public class CellRunable implements Runnable {
static int piao = 100;
static Object obj=new Object();
@Override
public void run() {
while (true) {
synchronized (obj){ //obj 就相当于一把锁 哪个线程一进入同步代码块,就会持有锁,那么这个把所不释放,其他线程就阻塞状态
if (piao > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//i-- i++ 先使用 后运算 //th3 //th2 100
System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
}
}
//哪个线程出了同步代码块就会释放锁
}
}
}
随意创造一个对象,类,然后通过 synchronized (){代码块} 方法将对象写进去,同时将可能出现多个线程同时操作的数据写入代码块中·。
或者
public static synchronized void maiPiao() {
//System.out.println(this);
// 相当于一把锁 哪个线程一进入同步代码块,就会持有锁,那么这个把所不释放,其他线程就阻塞状态
if (piao > 0) {
//模拟延迟
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
}
}
静态同步方法使用的是当前类的字节码文件对象,也就是说你也可以再这个类里再创建一个方法,该方法带有锁,然后通过调方法即可。
2.Lock锁(JDK5以后提供)
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock(); //加锁
if (piao > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
}
lock.unlock(); //释放锁
}
死锁
两个或者两个以上的线程, 在抢占CPU的执行权的时候, 都处于等待状态,程序无限运行
LockeInterface接口
public interface LockeInterface {
//定义两把锁
public static final Object objA=new Object();
public static final Object objB=new Object();
}
测试区
MyThread th1 = new MyThread(true);
MyThread th2 = new MyThread(false);
th1.start();
th2.start();
线程区
public class MyThread extends Thread {
boolean b;
public MyThread(boolean b) {
this.b = b;
}
@Override
public void run() {
if (b) {
synchronized (LockeInterface.objA) {
System.out.println("true objA 进来了");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (LockeInterface.objB) {
System.out.println("true objB 进来了");
}
}
} else {
synchronized (LockeInterface.objB) {
System.out.println("false objB 进来了");
synchronized (LockeInterface.objA) {
System.out.println("false objA 进来了");
}
}
}
}
}